diff options
author | Chris Sherlock <chris.sherlock79@gmail.com> | 2014-04-15 00:13:51 +1000 |
---|---|---|
committer | Chris Sherlock <chris.sherlock79@gmail.com> | 2014-04-16 07:33:58 +1000 |
commit | d92ee5d8bebdd6f120c7478127a1be5f78d4b1af (patch) | |
tree | 9bae335954f2182e786f97db10d865df21d5ac77 /vcl | |
parent | 5a35cb3e7fdb67f4f75435ab8869f8d973ae5daf (diff) |
Split outdev3.cxx
Split outdev3.cxx into font and text functions
Change-Id: I535dbbce055246865d4d5b62fb1ea5b991fb4663
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/Library_vcl.mk | 3 | ||||
-rw-r--r-- | vcl/source/outdev/font.cxx | 2397 | ||||
-rw-r--r-- | vcl/source/outdev/text.cxx (renamed from vcl/source/outdev/outdev3.cxx) | 2305 |
3 files changed, 2399 insertions, 2306 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index b6660074c8e6..b1fd7e8d52fe 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -242,7 +242,8 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/outdev/blend \ vcl/source/outdev/mask \ vcl/source/outdev/bitmap \ - vcl/source/outdev/outdev3 \ + vcl/source/outdev/font \ + vcl/source/outdev/text \ vcl/source/outdev/pixel \ vcl/source/outdev/rect \ vcl/source/outdev/line \ diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx new file mode 100644 index 000000000000..c1565f743b14 --- /dev/null +++ b/vcl/source/outdev/font.cxx @@ -0,0 +1,2397 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "i18nlangtag/mslangid.hxx" +#include "i18nlangtag/languagetag.hxx" + +#include "rtl/tencinfo.h" +#include "rtl/logfile.hxx" + +#include "tools/debug.hxx" +#include "tools/poly.hxx" + +#include "basegfx/polygon/b2dpolygon.hxx" +#include "basegfx/polygon/b2dpolypolygon.hxx" +#include "basegfx/matrix/b2dhommatrix.hxx" + +#include "vcl/metric.hxx" +#include "vcl/metaact.hxx" +#include "vcl/gdimtf.hxx" +#include "vcl/virdev.hxx" +#include "vcl/print.hxx" +#include "vcl/event.hxx" +#include "vcl/window.hxx" +#include "vcl/svapp.hxx" +#include "vcl/bmpacc.hxx" +#include "vcl/outdev.hxx" +#include "vcl/edit.hxx" +#include <vcl/settings.hxx> +// declare system types in sysdata.hxx +#include <svsys.h> +#include "vcl/sysdata.hxx" +#include "vcl/unohelp.hxx" +#include "vcl/controllayout.hxx" + +#include "salgdi.hxx" +#include "sallayout.hxx" +#include "svdata.hxx" +#include "impfont.hxx" +#include "outdata.hxx" +#include "outfont.hxx" +#include "outdev.h" +#include "PhysicalFontCollection.hxx" +#include "PhysicalFontFace.hxx" +#include "PhysicalFontFamily.hxx" + +#include "textlayout.hxx" +#include "svids.hrc" +#include "window.h" + +#include "unotools/fontcvt.hxx" +#include "unotools/fontcfg.hxx" + +#include "osl/file.h" + +#include <config_graphite.h> +#if ENABLE_GRAPHITE +#include "graphite_features.hxx" +#endif + +#include "../gdi/pdfwriter_impl.hxx" + +#include "com/sun/star/beans/PropertyValues.hpp" +#include "com/sun/star/i18n/XBreakIterator.hpp" +#include "com/sun/star/i18n/WordType.hpp" +#include "com/sun/star/linguistic2/LinguServiceManager.hpp" +#include <comphelper/processfactory.hxx> + +#include "sal/alloca.h" + +#include <cmath> +#include <cstring> + +#include <memory> +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::rtl; +using namespace ::vcl; +using namespace ::utl; + +void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY, + int nOrientation ) +{ + if ( (nOrientation >= 0) && !(nOrientation % 900) ) + { + if ( (nOrientation >= 3600) ) + nOrientation %= 3600; + + if ( nOrientation ) + { + rX -= nOriginX; + rY -= nOriginY; + + if ( nOrientation == 900 ) + { + long nTemp = rX; + rX = rY; + rY = -nTemp; + } + else if ( nOrientation == 1800 ) + { + rX = -rX; + rY = -rY; + } + else /* ( nOrientation == 2700 ) */ + { + long nTemp = rX; + rX = -rY; + rY = nTemp; + } + + rX += nOriginX; + rY += nOriginY; + } + } + else + { + double nRealOrientation = nOrientation*F_PI1800; + double nCos = cos( nRealOrientation ); + double nSin = sin( nRealOrientation ); + + // Translation... + long nX = rX-nOriginX; + long nY = rY-nOriginY; + + // Rotation... + rX = +((long)(nCos*nX + nSin*nY)) + nOriginX; + rY = -((long)(nSin*nX - nCos*nY)) + nOriginY; + } +} + +void OutputDevice::ImplClearFontData( const bool bNewFontLists ) +{ + // the currently selected logical font is no longer needed + if ( mpFontEntry ) + { + mpFontCache->Release( mpFontEntry ); + mpFontEntry = NULL; + } + + mbInitFont = true; + mbNewFont = true; + + if ( bNewFontLists ) + { + if ( mpGetDevFontList ) + { + delete mpGetDevFontList; + mpGetDevFontList = NULL; + } + if ( mpGetDevSizeList ) + { + delete mpGetDevSizeList; + mpGetDevSizeList = NULL; + } + + // release all physically selected fonts on this device + if( ImplGetGraphics() ) + mpGraphics->ReleaseFonts(); + } + +// if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter ) + { + ImplSVData* pSVData = ImplGetSVData(); + + if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache ) + mpFontCache->Invalidate(); + + if ( bNewFontLists ) + { + // we need a graphics + if ( ImplGetGraphics() ) + { + if( mpFontCollection && mpFontCollection != pSVData->maGDIData.mpScreenFontList ) + mpFontCollection->Clear(); + + if( mpPDFWriter ) + { + if( mpFontCollection && mpFontCollection != pSVData->maGDIData.mpScreenFontList ) + delete mpFontCollection; + if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache ) + delete mpFontCache; + mpFontCollection = 0; + mpFontCache = 0; + } + } + } + } + + // also update child windows if needed + if ( GetOutDevType() == OUTDEV_WINDOW ) + { + Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->ImplClearFontData( true ); + pChild = pChild->mpWindowImpl->mpNext; + } + } +} + +void OutputDevice::ImplRefreshFontData( const bool bNewFontLists ) +{ +// if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter ) + { + ImplSVData* pSVData = ImplGetSVData(); + + if ( bNewFontLists ) + { + // we need a graphics + if ( ImplGetGraphics() ) + { + if( mpPDFWriter ) + { + mpFontCollection = pSVData->maGDIData.mpScreenFontList->Clone( true, true ); + mpFontCache = new ImplFontCache(); + } + else + { + mpGraphics->GetDevFontList( mpFontCollection ); + } + } + } + } + + // also update child windows if needed + if ( GetOutDevType() == OUTDEV_WINDOW ) + { + Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->ImplRefreshFontData( true ); + pChild = pChild->mpWindowImpl->mpNext; + } + } +} + +void OutputDevice::ImplUpdateFontData( bool bNewFontLists ) +{ + ImplClearFontData( bNewFontLists ); + ImplRefreshFontData( bNewFontLists ); +} + +void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + ImplUpdateFontDataForAllFrames( &OutputDevice::ImplClearFontData, bNewFontLists ); + + // clear global font lists to have them updated + pSVData->maGDIData.mpScreenFontCache->Invalidate(); + if ( bNewFontLists ) + { + pSVData->maGDIData.mpScreenFontList->Clear(); + Window * pFrame = pSVData->maWinData.mpFirstFrame; + if ( pFrame ) + { + if ( pFrame->ImplGetGraphics() ) + { + // Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler + OutputDevice *pDevice = (OutputDevice*)pFrame; + pDevice->mpGraphics->ClearDevFontCache(); + pDevice->mpGraphics->GetDevFontList(pFrame->mpWindowImpl->mpFrameData->mpFontCollection); + } + } + } + + ImplUpdateFontDataForAllFrames( &OutputDevice::ImplRefreshFontData, bNewFontLists ); +} + +void OutputDevice::ImplUpdateFontDataForAllFrames( const FontUpdateHandler_t pHdl, const bool bNewFontLists ) +{ + ImplSVData* const pSVData = ImplGetSVData(); + + // update all windows + Window* pFrame = pSVData->maWinData.mpFirstFrame; + while ( pFrame ) + { + ( pFrame->*pHdl )( bNewFontLists ); + + Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap; + while ( pSysWin ) + { + ( pSysWin->*pHdl )( bNewFontLists ); + pSysWin = pSysWin->mpWindowImpl->mpNextOverlap; + } + + pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame; + } + + // update all virtual devices + VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev; + while ( pVirDev ) + { + ( pVirDev->*pHdl )( bNewFontLists ); + pVirDev = pVirDev->mpNext; + } + + // update all printers + Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter; + while ( pPrinter ) + { + ( pPrinter->*pHdl )( bNewFontLists ); + pPrinter = pPrinter->mpNext; + } +} + +void OutputDevice::BeginFontSubstitution() +{ + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maGDIData.mbFontSubChanged = false; +} + +void OutputDevice::EndFontSubstitution() +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( pSVData->maGDIData.mbFontSubChanged ) + { + ImplUpdateAllFontData( false ); + + Application* pApp = GetpApp(); + DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION ); + pApp->DataChanged( aDCEvt ); + pApp->NotifyAllWindows( aDCEvt ); + pSVData->maGDIData.mbFontSubChanged = false; + } +} + +void OutputDevice::AddFontSubstitute( const OUString& rFontName, + const OUString& rReplaceFontName, + sal_uInt16 nFlags ) +{ + ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; + if( !rpSubst ) + rpSubst = new ImplDirectFontSubstitution(); + rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags ); + ImplGetSVData()->maGDIData.mbFontSubChanged = true; +} + +void ImplDirectFontSubstitution::AddFontSubstitute( const OUString& rFontName, + const OUString& rSubstFontName, sal_uInt16 nFlags ) +{ + maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) ); +} + +ImplFontSubstEntry::ImplFontSubstEntry( const OUString& rFontName, + const OUString& rSubstFontName, sal_uInt16 nSubstFlags ) +: maName( rFontName ) +, maReplaceName( rSubstFontName ) +, mnFlags( nSubstFlags ) +{ + maSearchName = rFontName; + maSearchReplaceName = rSubstFontName; + GetEnglishSearchFontName( maSearchName ); + GetEnglishSearchFontName( maSearchReplaceName ); +} + +void OutputDevice::RemoveFontSubstitute( sal_uInt16 n ) +{ + ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; + if( pSubst ) + pSubst->RemoveFontSubstitute( n ); +} + +void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex ) +{ + FontSubstList::iterator it = maFontSubstList.begin(); + for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ; + if( it != maFontSubstList.end() ) + maFontSubstList.erase( it ); +} + +sal_uInt16 OutputDevice::GetFontSubstituteCount() +{ + const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; + if( !pSubst ) + return 0; + int nCount = pSubst->GetFontSubstituteCount(); + return (sal_uInt16)nCount; +} + +bool ImplDirectFontSubstitution::FindFontSubstitute( OUString& rSubstName, + const OUString& rSearchName, sal_uInt16 nFlags ) const +{ + // TODO: get rid of O(N) searches + FontSubstList::const_iterator it = maFontSubstList.begin(); + for(; it != maFontSubstList.end(); ++it ) + { + const ImplFontSubstEntry& rEntry = *it; + if( ((rEntry.mnFlags & nFlags) || !nFlags) + && (rEntry.maSearchName == rSearchName) ) + { + rSubstName = rEntry.maSearchReplaceName; + return true; + } + } + + return false; +} + +void ImplFontSubstitute( OUString& rFontName ) +{ +#ifdef DBG_UTIL + OUString aTempName = rFontName; + GetEnglishSearchFontName( aTempName ); + DBG_ASSERT( aTempName == rFontName, "ImplFontSubstitute() called without a searchname" ); +#endif + + OUString aSubstFontName; + + // apply user-configurable font replacement (eg, from the list in Tools->Options) + const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; + if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) ) + { + rFontName = aSubstFontName; + return; + } +} + +//hidpi TODO: This routine has hard-coded font-sizes that break places such as DialControl +Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang, + sal_uLong nFlags, const OutputDevice* pOutDev ) +{ + if (!pOutDev) // default is NULL + pOutDev = Application::GetDefaultDevice(); + + LanguageTag aLanguageTag( + ( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW ) ? + Application::GetSettings().GetUILanguageTag() : + LanguageTag( eLang )); + + utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get(); + OUString aDefault = rDefaults.getDefaultFont( aLanguageTag, nType ); + OUString aSearch; + + if( !aDefault.isEmpty() ) + aSearch = aDefault; + else + aSearch = rDefaults.getUserInterfaceFont( aLanguageTag ); // use the UI font as a fallback + + Font aFont; + aFont.SetPitch( PITCH_VARIABLE ); + + switch ( nType ) + { + case DEFAULTFONT_SANS_UNICODE: + case DEFAULTFONT_UI_SANS: + aFont.SetFamily( FAMILY_SWISS ); + break; + + case DEFAULTFONT_SANS: + case DEFAULTFONT_LATIN_HEADING: + case DEFAULTFONT_LATIN_SPREADSHEET: + case DEFAULTFONT_LATIN_DISPLAY: + aFont.SetFamily( FAMILY_SWISS ); + break; + + case DEFAULTFONT_SERIF: + case DEFAULTFONT_LATIN_TEXT: + case DEFAULTFONT_LATIN_PRESENTATION: + aFont.SetFamily( FAMILY_ROMAN ); + break; + + case DEFAULTFONT_FIXED: + case DEFAULTFONT_LATIN_FIXED: + case DEFAULTFONT_UI_FIXED: + aFont.SetPitch( PITCH_FIXED ); + aFont.SetFamily( FAMILY_MODERN ); + break; + + case DEFAULTFONT_SYMBOL: + aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL ); + break; + + case DEFAULTFONT_CJK_TEXT: + case DEFAULTFONT_CJK_PRESENTATION: + case DEFAULTFONT_CJK_SPREADSHEET: + case DEFAULTFONT_CJK_HEADING: + case DEFAULTFONT_CJK_DISPLAY: + aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later... + break; + + case DEFAULTFONT_CTL_TEXT: + case DEFAULTFONT_CTL_PRESENTATION: + case DEFAULTFONT_CTL_SPREADSHEET: + case DEFAULTFONT_CTL_HEADING: + case DEFAULTFONT_CTL_DISPLAY: + aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later... + break; + } + + if ( !aSearch.isEmpty() ) + { + aFont.SetHeight( 12 ); // corresponds to nDefaultHeight + aFont.SetWeight( WEIGHT_NORMAL ); + aFont.SetLanguage( eLang ); + + if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW ) + aFont.SetCharSet( osl_getThreadTextEncoding() ); + + // Should we only return available fonts on the given device + if ( pOutDev ) + { + pOutDev->ImplInitFontList(); + + // Search Font in the FontList + OUString aName; + OUString aSearchName; + sal_Int32 nIndex = 0; + do + { + aSearchName = GetNextFontToken( aSearch, nIndex ); + GetEnglishSearchFontName( aSearchName ); + PhysicalFontFamily* pFontFamily = pOutDev->mpFontCollection->ImplFindBySearchName( aSearchName ); + if( pFontFamily ) + { + AddTokenFontName( aName, pFontFamily->GetFamilyName() ); + if( nFlags & DEFAULTFONT_FLAGS_ONLYONE ) + break; + } + } + while ( nIndex != -1 ); + aFont.SetName( aName ); + } + + // No Name, than set all names + if ( aFont.GetName().isEmpty() ) + { + if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE ) + { + if( !pOutDev ) + { + SAL_WARN ("vcl.gdi", "No default window has been set for the application - we really shouldn't be able to get here"); + sal_Int32 nIndex = 0; + aFont.SetName( aSearch.getToken( 0, ';', nIndex ) ); + } + else + { + pOutDev->ImplInitFontList(); + + aFont.SetName( aSearch ); + + // convert to pixel height + Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() ); + if ( !aSize.Height() ) + { + // use default pixel height only when logical height is zero + if ( aFont.GetHeight() ) + aSize.Height() = 1; + else + aSize.Height() = (12*pOutDev->mnDPIY)/72; + } + + // use default width only when logical width is zero + if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) ) + aSize.Width() = 1; + + // get the name of the first available font + float fExactHeight = static_cast<float>(aSize.Height()); + ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontCollection, aFont, aSize, fExactHeight ); + if (pEntry) + { + if( pEntry->maFontSelData.mpFontData ) + aFont.SetName( pEntry->maFontSelData.mpFontData->GetFamilyName() ); + else + aFont.SetName( pEntry->maFontSelData.maTargetName ); + } + } + } + else + aFont.SetName( aSearch ); + } + } + +#if OSL_DEBUG_LEVEL > 2 + const char* s = "DEFAULTFONT_SANS_UNKNOWN"; + switch ( nType ) + { + case DEFAULTFONT_SANS_UNICODE: s = "DEFAULTFONT_SANS_UNICODE"; break; + case DEFAULTFONT_UI_SANS: s = "DEFAULTFONT_UI_SANS"; break; + + case DEFAULTFONT_SANS: s = "DEFAULTFONT_SANS"; break; + case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break; + case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break; + case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break; + + case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break; + case DEFAULTFONT_LATIN_TEXT: s = "DEFAULTFONT_LATIN_TEXT"; break; + case DEFAULTFONT_LATIN_PRESENTATION: s = "DEFAULTFONT_LATIN_PRESENTATION"; break; + + case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break; + case DEFAULTFONT_LATIN_FIXED: s = "DEFAULTFONT_LATIN_FIXED"; break; + case DEFAULTFONT_UI_FIXED: s = "DEFAULTFONT_UI_FIXED"; break; + + case DEFAULTFONT_SYMBOL: s = "DEFAULTFONT_SYMBOL"; break; + + case DEFAULTFONT_CJK_TEXT: s = "DEFAULTFONT_CJK_TEXT"; break; + case DEFAULTFONT_CJK_PRESENTATION: s = "DEFAULTFONT_CJK_PRESENTATION"; break; + case DEFAULTFONT_CJK_SPREADSHEET: s = "DEFAULTFONT_CJK_SPREADSHEET"; break; + case DEFAULTFONT_CJK_HEADING: s = "DEFAULTFONT_CJK_HEADING"; break; + case DEFAULTFONT_CJK_DISPLAY: s = "DEFAULTFONT_CJK_DISPLAY"; break; + + case DEFAULTFONT_CTL_TEXT: s = "DEFAULTFONT_CTL_TEXT"; break; + case DEFAULTFONT_CTL_PRESENTATION: s = "DEFAULTFONT_CTL_PRESENTATION"; break; + case DEFAULTFONT_CTL_SPREADSHEET: s = "DEFAULTFONT_CTL_SPREADSHEET"; break; + case DEFAULTFONT_CTL_HEADING: s = "DEFAULTFONT_CTL_HEADING"; break; + case DEFAULTFONT_CTL_DISPLAY: s = "DEFAULTFONT_CTL_DISPLAY"; break; + } + fprintf( stderr, " OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n", + s, eLang, nFlags, + OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr() + ); +#endif + + return aFont; +} + +ImplFontEntry::ImplFontEntry( const FontSelectPattern& rFontSelData ) + : maFontSelData( rFontSelData ) + , maMetric( rFontSelData ) + , mpConversion( NULL ) + , mnLineHeight( 0 ) + , mnRefCount( 1 ) + , mnSetFontFlags( 0 ) + , mnOwnOrientation( 0 ) + , mnOrientation( 0 ) + , mbInit( false ) + , mpUnicodeFallbackList( NULL ) +{ + maFontSelData.mpFontEntry = this; +} + +ImplFontEntry::~ImplFontEntry() +{ + delete mpUnicodeFallbackList; +} + +size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const +{ + boost::hash<sal_UCS4> a; + boost::hash<int > b; + return a(rData.first) ^ b(rData.second); +} + +void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName ) +{ + if( !mpUnicodeFallbackList ) + mpUnicodeFallbackList = new UnicodeFallbackList; + (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName; +} + +bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, OUString* pFontName ) const +{ + if( !mpUnicodeFallbackList ) + return false; + + UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) ); + if( it == mpUnicodeFallbackList->end() ) + return false; + + *pFontName = (*it).second; + return true; +} + +void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName ) +{ +// DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" ); + UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) ); +// DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" ); + if( it == mpUnicodeFallbackList->end() ) + return; + if( (*it).second == rFontName ) + mpUnicodeFallbackList->erase( it ); +} + +FontSelectPatternAttributes::FontSelectPatternAttributes( const Font& rFont, + const OUString& rSearchName, const Size& rSize, float fExactHeight ) + : maSearchName( rSearchName ) + , mnWidth( rSize.Width() ) + , mnHeight( rSize.Height() ) + , mfExactHeight( fExactHeight) + , mnOrientation( rFont.GetOrientation() ) + , meLanguage( rFont.GetLanguage() ) + , mbVertical( rFont.IsVertical() ) + , mbNonAntialiased( false ) + , mbEmbolden( false ) +{ + maTargetName = GetFamilyName(); + + rFont.GetFontAttributes( *this ); + + // normalize orientation between 0 and 3600 + if( 3600 <= (unsigned)mnOrientation ) + { + if( mnOrientation >= 0 ) + mnOrientation %= 3600; + else + mnOrientation = 3600 - (-mnOrientation % 3600); + } + + // normalize width and height + if( mnHeight < 0 ) + mnHeight = -mnHeight; + if( mnWidth < 0 ) + mnWidth = -mnWidth; +} + +FontSelectPattern::FontSelectPattern( const Font& rFont, + const OUString& rSearchName, const Size& rSize, float fExactHeight) + : FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight) + , mpFontData( NULL ) + , mpFontEntry( NULL ) +{ +} + +// NOTE: this ctor is still used on Windows. Do not remove. +#ifdef WNT +FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData, + const Size& rSize, float fExactHeight, int nOrientation, bool bVertical ) + : ImplFontAttributes( rFontData ) + , mnWidth( rSize.Width() ) + , mnHeight( rSize.Height() ) + , mfExactHeight( fExactHeight ) + , mnOrientation( nOrientation ) + , meLanguage( 0 ) + , mbVertical( bVertical ) + , mbNonAntialiased( false ) + , mbEmbolden( false ) +{ + maTargetName = maSearchName = GetFamilyName(); + // NOTE: no normalization for width/height/orientation +} + +FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData, + const Size& rSize, float fExactHeight, int nOrientation, bool bVertical ) + : FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical) + , mpFontData( &rFontData ) + , mpFontEntry( NULL ) +{ +} +#endif + +void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes) +{ + static_cast<FontSelectPatternAttributes&>(*this) = rAttributes; +} + +size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const +{ + return rFSD.hashCode(); +} + +size_t FontSelectPatternAttributes::hashCode() const +{ + // TODO: does it pay off to improve this hash function? + static FontNameHash aFontNameHash; + size_t nHash = aFontNameHash( maSearchName ); +#if ENABLE_GRAPHITE + // check for features and generate a unique hash if necessary + if (maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + != -1) + { + nHash = aFontNameHash( maTargetName ); + } +#endif + nHash += 11 * mnHeight; + nHash += 19 * GetWeight(); + nHash += 29 * GetSlant(); + nHash += 37 * mnOrientation; + nHash += 41 * meLanguage; + if( mbVertical ) + nHash += 53; + return nHash; +} + +bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const +{ + if (static_cast<const ImplFontAttributes&>(*this) != static_cast<const ImplFontAttributes&>(rOther)) + return false; + + if (maTargetName != rOther.maTargetName) + return false; + + if (maSearchName != rOther.maSearchName) + return false; + + if (mnWidth != rOther.mnWidth) + return false; + + if (mnHeight != rOther.mnHeight) + return false; + + if (mfExactHeight != rOther.mfExactHeight) + return false; + + if (mnOrientation != rOther.mnOrientation) + return false; + + if (meLanguage != rOther.meLanguage) + return false; + + if (mbVertical != rOther.mbVertical) + return false; + + if (mbNonAntialiased != rOther.mbNonAntialiased) + return false; + + if (mbEmbolden != rOther.mbEmbolden) + return false; + + if (maItalicMatrix != rOther.maItalicMatrix) + return false; + + return true; +} + +bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const +{ + // check normalized font family name + if( rA.maSearchName != rB.maSearchName ) + return false; + + // check font transformation + if( (rA.mnHeight != rB.mnHeight) + || (rA.mnWidth != rB.mnWidth) + || (rA.mnOrientation != rB.mnOrientation) ) + return false; + + // check mapping relevant attributes + if( (rA.mbVertical != rB.mbVertical) + || (rA.meLanguage != rB.meLanguage) ) + return false; + + // check font face attributes + if( (rA.GetWeight() != rB.GetWeight()) + || (rA.GetSlant() != rB.GetSlant()) +// || (rA.meFamily != rB.meFamily) // TODO: remove this mostly obsolete member + || (rA.GetPitch() != rB.GetPitch()) ) + return false; + + // check style name + if( rA.GetStyleName() != rB.GetStyleName() ) + return false; + + // Symbol fonts may recode from one type to another So they are only + // safely equivalent for equal targets + if ( + (rA.mpFontData && rA.mpFontData->IsSymbolFont()) || + (rB.mpFontData && rB.mpFontData->IsSymbolFont()) + ) + { + if (rA.maTargetName != rB.maTargetName) + return false; + } + +#if ENABLE_GRAPHITE + // check for features + if ((rA.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + != -1 || + rB.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + != -1) && rA.maTargetName != rB.maTargetName) + return false; +#endif + + if (rA.mbEmbolden != rB.mbEmbolden) + return false; + + if (rA.maItalicMatrix != rB.maItalicMatrix) + return false; + + return true; +} + +ImplFontCache::ImplFontCache() +: mpFirstEntry( NULL ), + mnRef0Count( 0 ) +{} + +ImplFontCache::~ImplFontCache() +{ + FontInstanceList::iterator it = maFontInstanceList.begin(); + for(; it != maFontInstanceList.end(); ++it ) + { + ImplFontEntry* pEntry = (*it).second; + delete pEntry; + } +} + +ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList, + const Font& rFont, const Size& rSize, float fExactHeight ) +{ + OUString aSearchName = rFont.GetName(); + + // initialize internal font request object + FontSelectPattern aFontSelData( rFont, aSearchName, rSize, fExactHeight ); + return GetFontEntry( pFontList, aFontSelData ); +} + +ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList, + FontSelectPattern& aFontSelData ) +{ + // check if a directly matching logical font instance is already cached, + // the most recently used font usually has a hit rate of >50% + ImplFontEntry *pEntry = NULL; + PhysicalFontFamily* pFontFamily = NULL; + IFSD_Equal aIFSD_Equal; + if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) ) + pEntry = mpFirstEntry; + else + { + FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData ); + if( it != maFontInstanceList.end() ) + pEntry = (*it).second; + } + + if( !pEntry ) // no direct cache hit + { + // find the best matching logical font family and update font selector accordingly + pFontFamily = pFontList->ImplFindByFont( aFontSelData ); + DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" ); + if( pFontFamily ) + aFontSelData.maSearchName = pFontFamily->GetSearchName(); + + // check if an indirectly matching logical font instance is already cached + FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData ); + if( it != maFontInstanceList.end() ) + { + // we have an indirect cache hit + pEntry = (*it).second; + } + } + + PhysicalFontFace* pFontData = NULL; + + if (!pEntry && pFontFamily)// no cache hit => find the best matching physical font face + { + bool bOrigWasSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont(); + pFontData = pFontFamily->FindBestFontFace( aFontSelData ); + aFontSelData.mpFontData = pFontData; + bool bNewIsSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont(); + + if (bNewIsSymbol != bOrigWasSymbol) + { + // it is possible, though generally unlikely, that at this point we + // will attempt to use a symbol font as a last-ditch fallback for a + // non-symbol font request or vice versa, and by changing + // aFontSelData.mpFontData to/from a symbol font we may now find + // something in the cache that can be reused which previously + // wasn't a candidate + FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData ); + if( it != maFontInstanceList.end() ) + pEntry = (*it).second; + } + } + + if( pEntry ) // cache hit => use existing font instance + { + // increase the font instance's reference count + if( !pEntry->mnRefCount++ ) + --mnRef0Count; + } + + if (!pEntry && pFontData)// still no cache hit => create a new font instance + { + // create a new logical font instance from this physical font face + pEntry = pFontData->CreateFontInstance( aFontSelData ); + + // if we're subtituting from or to a symbol font we may need a symbol + // conversion table + if( pFontData->IsSymbolFont() || aFontSelData.IsSymbolFont() ) + { + if( aFontSelData.maTargetName != aFontSelData.maSearchName ) + pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName ); + } + +#ifdef MACOSX + //It might be better to dig out the font version of the target font + //to see if it's a modern re-coded apple symbol font in case that + //font shows up on a different platform + if (!pEntry->mpConversion && + aFontSelData.maTargetName.equalsIgnoreAsciiCase("symbol") && + aFontSelData.maSearchName.equalsIgnoreAsciiCase("symbol")) + { + pEntry->mpConversion = ConvertChar::GetRecodeData( OUString("Symbol"), OUString("AppleSymbol") ); + } +#endif + + // add the new entry to the cache + maFontInstanceList[ aFontSelData ] = pEntry; + } + + mpFirstEntry = pEntry; + return pEntry; +} + +ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( PhysicalFontCollection* pFontCollection, + FontSelectPattern& rFontSelData, int nFallbackLevel, OUString& rMissingCodes ) +{ + // get a candidate font for glyph fallback + // unless the previously selected font got a device specific substitution + // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it + if( nFallbackLevel >= 1) + { + PhysicalFontFamily* pFallbackData = NULL; + + //fdo#33898 If someone has EUDC installed then they really want that to + //be used as the first-choice glyph fallback seeing as it's filled with + //private area codes with don't make any sense in any other font so + //prioritise it here if it's available. Ideally we would remove from + //rMissingCodes all the glyphs which it is able to resolve as an + //optimization, but that's tricky to achieve cross-platform without + //sufficient heavy-weight code that's likely to undo the value of the + //optimization + if (nFallbackLevel == 1) + pFallbackData = pFontCollection->FindFontFamily(OUString("EUDC")); + if (!pFallbackData) + pFallbackData = pFontCollection->GetGlyphFallbackFont(rFontSelData, rMissingCodes, nFallbackLevel-1); + // escape when there are no font candidates + if( !pFallbackData ) + return NULL; + // override the font name + rFontSelData.SetFamilyName( pFallbackData->GetFamilyName() ); + // clear the cached normalized name + rFontSelData.maSearchName = ""; + } + + ImplFontEntry* pFallbackFont = GetFontEntry( pFontCollection, rFontSelData ); + return pFallbackFont; +} + +void ImplFontCache::Release( ImplFontEntry* pEntry ) +{ + static const int FONTCACHE_MAX = 50; + + DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" ); + if( --pEntry->mnRefCount > 0 ) + return; + + if( ++mnRef0Count < FONTCACHE_MAX ) + return; + + // remove unused entries from font instance cache + FontInstanceList::iterator it_next = maFontInstanceList.begin(); + while( it_next != maFontInstanceList.end() ) + { + FontInstanceList::iterator it = it_next++; + ImplFontEntry* pFontEntry = (*it).second; + if( pFontEntry->mnRefCount > 0 ) + continue; + + maFontInstanceList.erase( it ); + delete pFontEntry; + --mnRef0Count; + DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" ); + + if( mpFirstEntry == pFontEntry ) + mpFirstEntry = NULL; + } + + DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" ); +} + +void ImplFontCache::Invalidate() +{ + // delete unreferenced entries + FontInstanceList::iterator it = maFontInstanceList.begin(); + for(; it != maFontInstanceList.end(); ++it ) + { + ImplFontEntry* pFontEntry = (*it).second; + if( pFontEntry->mnRefCount > 0 ) + continue; + + delete pFontEntry; + --mnRef0Count; + } + + // #112304# make sure the font cache is really clean + mpFirstEntry = NULL; + maFontInstanceList.clear(); + + DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" ); +} + +FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const Font& rFont ) +{ + FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark(); + + // If no Position is set, then calculate the default position, which + // depends on the language + if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) ) + { + LanguageType eLang = rFont.GetLanguage(); + // In Chinese Simplified the EmphasisMarks are below/left + if (MsLangId::isSimplifiedChinese(eLang)) + nEmphasisMark |= EMPHASISMARK_POS_BELOW; + else + { + eLang = rFont.GetCJKContextLanguage(); + // In Chinese Simplified the EmphasisMarks are below/left + if (MsLangId::isSimplifiedChinese(eLang)) + nEmphasisMark |= EMPHASISMARK_POS_BELOW; + else + nEmphasisMark |= EMPHASISMARK_POS_ABOVE; + } + } + + return nEmphasisMark; +} + +void OutputDevice::ImplInitFontList() const +{ + if( !mpFontCollection->Count() ) + { + if( mpGraphics || ImplGetGraphics() ) + { + SAL_INFO( "vcl.gdi", "OutputDevice::ImplInitFontList()" ); + mpGraphics->GetDevFontList( mpFontCollection ); + + // There is absolutely no way there should be no fonts available on the device + if( !mpFontCollection->Count() ) + { + OUString aError( "Application error: no fonts and no vcl resource found on your system" ); + ResMgr* pMgr = ImplGetResMgr(); + if( pMgr ) + { + OUString aResStr(ResId(SV_ACCESSERROR_NO_FONTS, *pMgr).toString()); + if( !aResStr.isEmpty() ) + aError = aResStr; + } + Application::Abort( aError ); + } + } + } +} + +void OutputDevice::ImplInitFont() const +{ + DBG_TESTSOLARMUTEX(); + + if (!mpFontEntry) + return; + + if ( mbInitFont ) + { + if ( meOutDevType != OUTDEV_PRINTER ) + { + // decide if antialiasing is appropriate + bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0; + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0); + bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight); + mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased; + } + + // select font in the device layers + mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 ); + mbInitFont = false; + } +} + +bool OutputDevice::ImplNewFont() const +{ + DBG_TESTSOLARMUTEX(); + + // get correct font list on the PDF writer if necessary + if( mpPDFWriter ) + { + const ImplSVData* pSVData = ImplGetSVData(); + if( mpFontCollection == pSVData->maGDIData.mpScreenFontList + || mpFontCache == pSVData->maGDIData.mpScreenFontCache ) + const_cast<OutputDevice&>(*this).ImplUpdateFontData( true ); + } + + if ( !mbNewFont ) + return true; + + // we need a graphics + if ( !mpGraphics && !ImplGetGraphics() ) + return false; + SalGraphics* pGraphics = mpGraphics; + ImplInitFontList(); + + // convert to pixel height + // TODO: replace integer based aSize completely with subpixel accurate type + float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) ); + Size aSize = ImplLogicToDevicePixel( maFont.GetSize() ); + if ( !aSize.Height() ) + { + // use default pixel height only when logical height is zero + if ( maFont.GetSize().Height() ) + aSize.Height() = 1; + else + aSize.Height() = (12*mnDPIY)/72; + fExactHeight = static_cast<float>(aSize.Height()); + } + + // select the default width only when logical width is zero + if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) ) + aSize.Width() = 1; + + // get font entry + ImplFontEntry* pOldEntry = mpFontEntry; + mpFontEntry = mpFontCache->GetFontEntry( mpFontCollection, maFont, aSize, fExactHeight ); + if( pOldEntry ) + mpFontCache->Release( pOldEntry ); + + ImplFontEntry* pFontEntry = mpFontEntry; + + if (!pFontEntry) + return false; + + // mark when lower layers need to get involved + mbNewFont = false; + if( pFontEntry != pOldEntry ) + mbInitFont = true; + + // select font when it has not been initialized yet + if ( !pFontEntry->mbInit ) + { + ImplInitFont(); + + // get metric data from device layers + if ( pGraphics ) + { + pFontEntry->mbInit = true; + + pFontEntry->maMetric.mnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation); + pGraphics->GetFontMetric( &(pFontEntry->maMetric) ); + + pFontEntry->maMetric.ImplInitTextLineSize( this ); + pFontEntry->maMetric.ImplInitAboveTextLineSize(); + + pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent; + + if( pFontEntry->maFontSelData.mnOrientation + && !pFontEntry->maMetric.mnOrientation + && (meOutDevType != OUTDEV_PRINTER) ) + { + pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation); + pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation; + } + else + pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation; + } + } + + // enable kerning array if requested + if ( maFont.GetKerning() & KERNING_FONTSPECIFIC ) + { + // TODO: test if physical font supports kerning and disable if not + if( pFontEntry->maMetric.mbKernableFont ) + mbKerning = true; + } + else + mbKerning = false; + if ( maFont.GetKerning() & KERNING_ASIAN ) + mbKerning = true; + + // calculate EmphasisArea + mnEmphasisAscent = 0; + mnEmphasisDescent = 0; + if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE ) + { + FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont ); + long nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000; + if ( nEmphasisHeight < 1 ) + nEmphasisHeight = 1; + if ( nEmphasisMark & EMPHASISMARK_POS_BELOW ) + mnEmphasisDescent = nEmphasisHeight; + else + mnEmphasisAscent = nEmphasisHeight; + } + + // calculate text offset depending on TextAlignment + TextAlign eAlign = maFont.GetAlign(); + if ( eAlign == ALIGN_BASELINE ) + { + mnTextOffX = 0; + mnTextOffY = 0; + } + else if ( eAlign == ALIGN_TOP ) + { + mnTextOffX = 0; + mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent; + if ( pFontEntry->mnOrientation ) + ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation ); + } + else // eAlign == ALIGN_BOTTOM + { + mnTextOffX = 0; + mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent; + if ( pFontEntry->mnOrientation ) + ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation ); + } + + mbTextLines = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) || + ((maFont.GetOverline() != UNDERLINE_NONE) && (maFont.GetOverline() != UNDERLINE_DONTKNOW)) || + ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW)); + mbTextSpecial = maFont.IsShadow() || maFont.IsOutline() || + (maFont.GetRelief() != RELIEF_NONE); + + // #95414# fix for OLE objects which use scale factors very creatively + if( mbMap && !aSize.Width() ) + { + int nOrigWidth = pFontEntry->maMetric.mnWidth; + float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY; + fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX; + int nNewWidth = (int)(nOrigWidth * fStretch + 0.5); + if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) ) + { + Size aOrigSize = maFont.GetSize(); + const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) ); + mbMap = false; + mbNewFont = true; + ImplNewFont(); // recurse once using stretched width + mbMap = true; + const_cast<Font&>(maFont).SetSize( aOrigSize ); + } + } + + return true; +} + +bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const +{ + if (maName != rOther.maName) + return false; + + if (maStyleName != rOther.maStyleName) + return false; + + if (meWeight != rOther.meWeight) + return false; + + if (meItalic != rOther.meItalic) + return false; + + if (meFamily != rOther.meFamily) + return false; + + if (mePitch != rOther.mePitch) + return false; + + if (meWidthType != rOther.meWidthType) + return false; + + if (mbSymbolFlag != rOther.mbSymbolFlag) + return false; + + return true; +} + +ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData ) + : ImplFontAttributes( rFontSelData ) + , mnWidth ( rFontSelData.mnWidth) + , mnOrientation( (short)(rFontSelData.mnOrientation)) + , mnAscent( 0 ) + , mnDescent( 0 ) + , mnIntLeading( 0 ) + , mnExtLeading( 0 ) + , mnSlant( 0 ) + , mnMinKashida( 0 ) + , mnUnderlineSize( 0 ) + , mnUnderlineOffset( 0 ) + , mnBUnderlineSize( 0 ) + , mnBUnderlineOffset( 0 ) + , mnDUnderlineSize( 0 ) + , mnDUnderlineOffset1( 0 ) + , mnDUnderlineOffset2( 0 ) + , mnWUnderlineSize( 0 ) + , mnWUnderlineOffset( 0 ) + , mnAboveUnderlineSize( 0 ) + , mnAboveUnderlineOffset( 0 ) + , mnAboveBUnderlineSize( 0 ) + , mnAboveBUnderlineOffset( 0 ) + , mnAboveDUnderlineSize( 0 ) + , mnAboveDUnderlineOffset1( 0 ) + , mnAboveDUnderlineOffset2( 0 ) + , mnAboveWUnderlineSize( 0 ) + , mnAboveWUnderlineOffset( 0 ) + , mnStrikeoutSize( 0 ) + , mnStrikeoutOffset( 0 ) + , mnBStrikeoutSize( 0 ) + , mnBStrikeoutOffset( 0 ) + , mnDStrikeoutSize( 0 ) + , mnDStrikeoutOffset1( 0 ) + , mnDStrikeoutOffset2( 0 ) +{ + // intialize the used font name + if( rFontSelData.mpFontData ) + { + SetFamilyName( rFontSelData.mpFontData->GetFamilyName() ); + SetStyleName( rFontSelData.mpFontData->GetStyleName() ); + mbDevice = rFontSelData.mpFontData->mbDevice; + mbKernableFont = true; + } + else + { + sal_Int32 nTokenPos = 0; + SetFamilyName( GetNextFontToken( rFontSelData.GetFamilyName(), nTokenPos ) ); + SetStyleName( rFontSelData.GetStyleName() ); + mbDevice = false; + mbKernableFont = false; + } +} + +void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev ) +{ + long nDescent = mnDescent; + if ( nDescent <= 0 ) + { + nDescent = mnAscent / 10; + if ( !nDescent ) + nDescent = 1; + } + + // #i55341# for some fonts it is not a good idea to calculate + // their text line metrics from the real font descent + // => work around this problem just for these fonts + if( 3*nDescent > mnAscent ) + nDescent = mnAscent / 3; + + long nLineHeight = ((nDescent*25)+50) / 100; + if ( !nLineHeight ) + nLineHeight = 1; + long nLineHeight2 = nLineHeight / 2; + if ( !nLineHeight2 ) + nLineHeight2 = 1; + + long nBLineHeight = ((nDescent*50)+50) / 100; + if ( nBLineHeight == nLineHeight ) + nBLineHeight++; + long nBLineHeight2 = nBLineHeight/2; + if ( !nBLineHeight2 ) + nBLineHeight2 = 1; + + long n2LineHeight = ((nDescent*16)+50) / 100; + if ( !n2LineHeight ) + n2LineHeight = 1; + long n2LineDY = n2LineHeight; + /* #117909# + * add some pixels to minimum double line distance on higher resolution devices + */ + long nMin2LineDY = 1 + pDev->ImplGetDPIY()/150; + if ( n2LineDY < nMin2LineDY ) + n2LineDY = nMin2LineDY; + long n2LineDY2 = n2LineDY/2; + if ( !n2LineDY2 ) + n2LineDY2 = 1; + + long nUnderlineOffset = mnDescent/2 + 1; + long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3); + + mnUnderlineSize = nLineHeight; + mnUnderlineOffset = nUnderlineOffset - nLineHeight2; + + mnBUnderlineSize = nBLineHeight; + mnBUnderlineOffset = nUnderlineOffset - nBLineHeight2; + + mnDUnderlineSize = n2LineHeight; + mnDUnderlineOffset1 = nUnderlineOffset - n2LineDY2 - n2LineHeight; + mnDUnderlineOffset2 = mnDUnderlineOffset1 + n2LineDY + n2LineHeight; + + long nWCalcSize = mnDescent; + if ( nWCalcSize < 6 ) + { + if ( (nWCalcSize == 1) || (nWCalcSize == 2) ) + mnWUnderlineSize = nWCalcSize; + else + mnWUnderlineSize = 3; + } + else + mnWUnderlineSize = ((nWCalcSize*50)+50) / 100; + + // #109280# the following line assures that wavelnes are never placed below the descent, however + // for most fonts the waveline then is drawn into the text, so we better keep the old solution + // pFontEntry->maMetric.mnWUnderlineOffset = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize; + mnWUnderlineOffset = nUnderlineOffset; + + mnStrikeoutSize = nLineHeight; + mnStrikeoutOffset = nStrikeoutOffset - nLineHeight2; + + mnBStrikeoutSize = nBLineHeight; + mnBStrikeoutOffset = nStrikeoutOffset - nBLineHeight2; + + mnDStrikeoutSize = n2LineHeight; + mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight; + mnDStrikeoutOffset2 = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight; +} + +void ImplFontMetricData::ImplInitAboveTextLineSize() +{ + long nIntLeading = mnIntLeading; + // TODO: assess usage of nLeading below (changed in extleading CWS) + // if no leading is available, we assume 15% of the ascent + if ( nIntLeading <= 0 ) + { + nIntLeading = mnAscent*15/100; + if ( !nIntLeading ) + nIntLeading = 1; + } + + long nLineHeight = ((nIntLeading*25)+50) / 100; + if ( !nLineHeight ) + nLineHeight = 1; + + long nBLineHeight = ((nIntLeading*50)+50) / 100; + if ( nBLineHeight == nLineHeight ) + nBLineHeight++; + + long n2LineHeight = ((nIntLeading*16)+50) / 100; + if ( !n2LineHeight ) + n2LineHeight = 1; + + long nCeiling = -mnAscent; + + mnAboveUnderlineSize = nLineHeight; + mnAboveUnderlineOffset = nCeiling + (nIntLeading - nLineHeight + 1) / 2; + + mnAboveBUnderlineSize = nBLineHeight; + mnAboveBUnderlineOffset = nCeiling + (nIntLeading - nBLineHeight + 1) / 2; + + mnAboveDUnderlineSize = n2LineHeight; + mnAboveDUnderlineOffset1 = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2; + mnAboveDUnderlineOffset2 = nCeiling + (nIntLeading + n2LineHeight + 1) / 2; + + long nWCalcSize = nIntLeading; + if ( nWCalcSize < 6 ) + { + if ( (nWCalcSize == 1) || (nWCalcSize == 2) ) + mnAboveWUnderlineSize = nWCalcSize; + else + mnAboveWUnderlineSize = 3; + } + else + mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100; + + mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2; +} + +void OutputDevice::ImplGetEmphasisMark( PolyPolygon& rPolyPoly, bool& rPolyLine, + Rectangle& rRect1, Rectangle& rRect2, + long& rYOff, long& rWidth, + FontEmphasisMark eEmphasis, + long nHeight, short /*nOrient*/ ) +{ + static const sal_uInt8 aAccentPolyFlags[24] = + { + 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2 + }; + + static const long aAccentPos[48] = + { + 78, 0, + 348, 79, + 599, 235, + 843, 469, + 938, 574, + 990, 669, + 990, 773, + 990, 843, + 964, 895, + 921, 947, + 886, 982, + 860, 999, + 825, 999, + 764, 999, + 721, 964, + 686, 895, + 625, 791, + 556, 660, + 469, 504, + 400, 400, + 261, 252, + 61, 61, + 0, 27, + 9, 0 + }; + + rWidth = 0; + rYOff = 0; + rPolyLine = false; + + if ( !nHeight ) + return; + + FontEmphasisMark nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE; + long nDotSize = 0; + switch ( nEmphasisStyle ) + { + case EMPHASISMARK_DOT: + // Dot has 55% of the height + nDotSize = (nHeight*550)/1000; + if ( !nDotSize ) + nDotSize = 1; + if ( nDotSize <= 2 ) + rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) ); + else + { + long nRad = nDotSize/2; + Polygon aPoly( Point( nRad, nRad ), nRad, nRad ); + rPolyPoly.Insert( aPoly ); + } + rYOff = ((nHeight*250)/1000)/2; // Center to the another EmphasisMarks + rWidth = nDotSize; + break; + + case EMPHASISMARK_CIRCLE: + // Dot has 80% of the height + nDotSize = (nHeight*800)/1000; + if ( !nDotSize ) + nDotSize = 1; + if ( nDotSize <= 2 ) + rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) ); + else + { + long nRad = nDotSize/2; + Polygon aPoly( Point( nRad, nRad ), nRad, nRad ); + rPolyPoly.Insert( aPoly ); + // BorderWidth is 15% + long nBorder = (nDotSize*150)/1000; + if ( nBorder <= 1 ) + rPolyLine = true; + else + { + Polygon aPoly2( Point( nRad, nRad ), + nRad-nBorder, nRad-nBorder ); + rPolyPoly.Insert( aPoly2 ); + } + } + rWidth = nDotSize; + break; + + case EMPHASISMARK_DISC: + // Dot has 80% of the height + nDotSize = (nHeight*800)/1000; + if ( !nDotSize ) + nDotSize = 1; + if ( nDotSize <= 2 ) + rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) ); + else + { + long nRad = nDotSize/2; + Polygon aPoly( Point( nRad, nRad ), nRad, nRad ); + rPolyPoly.Insert( aPoly ); + } + rWidth = nDotSize; + break; + + case EMPHASISMARK_ACCENT: + // Dot has 80% of the height + nDotSize = (nHeight*800)/1000; + if ( !nDotSize ) + nDotSize = 1; + if ( nDotSize <= 2 ) + { + if ( nDotSize == 1 ) + { + rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) ); + rWidth = nDotSize; + } + else + { + rRect1 = Rectangle( Point(), Size( 1, 1 ) ); + rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) ); + } + } + else + { + Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2, + (const Point*)aAccentPos, + aAccentPolyFlags ); + double dScale = ((double)nDotSize)/1000.0; + aPoly.Scale( dScale, dScale ); + Polygon aTemp; + aPoly.AdaptiveSubdivide( aTemp ); + Rectangle aBoundRect = aTemp.GetBoundRect(); + rWidth = aBoundRect.GetWidth(); + nDotSize = aBoundRect.GetHeight(); + rPolyPoly.Insert( aTemp ); + } + break; + } + + // calculate position + long nOffY = 1+(mnDPIY/300); // one visible pixel space + long nSpaceY = nHeight-nDotSize; + if ( nSpaceY >= nOffY*2 ) + rYOff += nOffY; + if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) ) + rYOff += nDotSize; +} + +void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY, + const PolyPolygon& rPolyPoly, bool bPolyLine, + const Rectangle& rRect1, const Rectangle& rRect2 ) +{ + if( IsRTLEnabled() ) + // --- RTL --- mirror at basex + nX = nBaseX - (nX - nBaseX - 1); + + nX -= mnOutOffX; + nY -= mnOutOffY; + + if ( rPolyPoly.Count() ) + { + if ( bPolyLine ) + { + Polygon aPoly = rPolyPoly.GetObject( 0 ); + aPoly.Move( nX, nY ); + DrawPolyLine( aPoly ); + } + else + { + PolyPolygon aPolyPoly = rPolyPoly; + aPolyPoly.Move( nX, nY ); + DrawPolyPolygon( aPolyPoly ); + } + } + + if ( !rRect1.IsEmpty() ) + { + Rectangle aRect( Point( nX+rRect1.Left(), + nY+rRect1.Top() ), rRect1.GetSize() ); + DrawRect( aRect ); + } + + if ( !rRect2.IsEmpty() ) + { + Rectangle aRect( Point( nX+rRect2.Left(), + nY+rRect2.Top() ), rRect2.GetSize() ); + + DrawRect( aRect ); + } +} + +void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout ) +{ + Color aOldLineColor = GetLineColor(); + Color aOldFillColor = GetFillColor(); + bool bOldMap = mbMap; + GDIMetaFile* pOldMetaFile = mpMetaFile; + mpMetaFile = NULL; + EnableMapMode( false ); + + FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont ); + PolyPolygon aPolyPoly; + Rectangle aRect1; + Rectangle aRect2; + long nEmphasisYOff; + long nEmphasisWidth; + long nEmphasisHeight; + bool bPolyLine; + + if ( nEmphasisMark & EMPHASISMARK_POS_BELOW ) + nEmphasisHeight = mnEmphasisDescent; + else + nEmphasisHeight = mnEmphasisAscent; + + ImplGetEmphasisMark( aPolyPoly, bPolyLine, + aRect1, aRect2, + nEmphasisYOff, nEmphasisWidth, + nEmphasisMark, + nEmphasisHeight, mpFontEntry->mnOrientation ); + + if ( bPolyLine ) + { + SetLineColor( GetTextColor() ); + SetFillColor(); + } + else + { + SetLineColor(); + SetFillColor( GetTextColor() ); + } + + Point aOffset = Point(0,0); + + if ( nEmphasisMark & EMPHASISMARK_POS_BELOW ) + aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff; + else + aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff; + + long nEmphasisWidth2 = nEmphasisWidth / 2; + long nEmphasisHeight2 = nEmphasisHeight / 2; + aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 ); + + Point aOutPoint; + Rectangle aRectangle; + for( int nStart = 0;;) + { + sal_GlyphId aGlyphId; + if( !rSalLayout.GetNextGlyphs( 1, &aGlyphId, aOutPoint, nStart ) ) + break; + + if( !mpGraphics->GetGlyphBoundRect( aGlyphId, aRectangle ) ) + continue; + + if( !rSalLayout.IsSpacingGlyph( aGlyphId ) ) + { + Point aAdjPoint = aOffset; + aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2; + if ( mpFontEntry->mnOrientation ) + ImplRotatePos( 0, 0, aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation ); + aOutPoint += aAdjPoint; + aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 ); + ImplDrawEmphasisMark( rSalLayout.DrawBase().X(), + aOutPoint.X(), aOutPoint.Y(), + aPolyPoly, bPolyLine, aRect1, aRect2 ); + } + } + + SetLineColor( aOldLineColor ); + SetFillColor( aOldFillColor ); + EnableMapMode( bOldMap ); + mpMetaFile = pOldMetaFile; +} + +void OutputDevice::SetFont( const Font& rNewFont ) +{ + + Font aFont( rNewFont ); + aFont.SetLanguage(rNewFont.GetLanguage()); + if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | DRAWMODE_SETTINGSTEXT | + DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL | + DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) ) + { + Color aTextColor( aFont.GetColor() ); + + if ( mnDrawMode & DRAWMODE_BLACKTEXT ) + aTextColor = Color( COL_BLACK ); + else if ( mnDrawMode & DRAWMODE_WHITETEXT ) + aTextColor = Color( COL_WHITE ); + else if ( mnDrawMode & DRAWMODE_GRAYTEXT ) + { + const sal_uInt8 cLum = aTextColor.GetLuminance(); + aTextColor = Color( cLum, cLum, cLum ); + } + else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT ) + aTextColor = GetSettings().GetStyleSettings().GetFontColor(); + + if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT ) + { + aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80, + (aTextColor.GetGreen() >> 1 ) | 0x80, + (aTextColor.GetBlue() >> 1 ) | 0x80 ); + } + + aFont.SetColor( aTextColor ); + + bool bTransFill = aFont.IsTransparent(); + if ( !bTransFill ) + { + Color aTextFillColor( aFont.GetFillColor() ); + + if ( mnDrawMode & DRAWMODE_BLACKFILL ) + aTextFillColor = Color( COL_BLACK ); + else if ( mnDrawMode & DRAWMODE_WHITEFILL ) + aTextFillColor = Color( COL_WHITE ); + else if ( mnDrawMode & DRAWMODE_GRAYFILL ) + { + const sal_uInt8 cLum = aTextFillColor.GetLuminance(); + aTextFillColor = Color( cLum, cLum, cLum ); + } + else if( mnDrawMode & DRAWMODE_SETTINGSFILL ) + aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor(); + else if ( mnDrawMode & DRAWMODE_NOFILL ) + { + aTextFillColor = Color( COL_TRANSPARENT ); + bTransFill = true; + } + + if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) ) + { + aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80, + (aTextFillColor.GetGreen() >> 1) | 0x80, + (aTextFillColor.GetBlue() >> 1) | 0x80 ); + } + + aFont.SetFillColor( aTextFillColor ); + } + } + + if ( mpMetaFile ) + { + mpMetaFile->AddAction( new MetaFontAction( aFont ) ); + // the color and alignment actions don't belong here + // TODO: get rid of them without breaking anything... + mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) ); + mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) ); + } + + if ( !maFont.IsSameInstance( aFont ) ) + { + // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color, + // because SetTextColor() is used for this. + // #i28759# maTextColor might have been changed behind our back, commit then, too. + if( aFont.GetColor() != COL_TRANSPARENT + && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) ) + { + maTextColor = aFont.GetColor(); + mbInitTextColor = true; + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) ); + } + maFont = aFont; + mbNewFont = true; + + if( mpAlphaVDev ) + { + // #i30463# + // Since SetFont might change the text color, apply that only + // selectively to alpha vdev (which normally paints opaque text + // with COL_BLACK) + if( aFont.GetColor() != COL_TRANSPARENT ) + { + mpAlphaVDev->SetTextColor( COL_BLACK ); + aFont.SetColor( COL_TRANSPARENT ); + } + + mpAlphaVDev->SetFont( aFont ); + } + } +} + +SalLayout* OutputDevice::getFallbackFont(ImplFontEntry &rFallbackFont, + FontSelectPattern &rFontSelData, int nFallbackLevel, + ImplLayoutArgs& rLayoutArgs) const +{ + rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel ); + + rLayoutArgs.ResetPos(); + SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel ); + + if (!pFallback) + return NULL; + + if (!pFallback->LayoutText(rLayoutArgs)) + { + // there is no need for a font that couldn't resolve anything + pFallback->Release(); + return NULL; + } + + pFallback->AdjustLayout( rLayoutArgs ); + + return pFallback; +} + +SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const +{ + // prepare multi level glyph fallback + MultiSalLayout* pMultiSalLayout = NULL; + ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns; + rLayoutArgs.PrepareFallback(); + rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK; + + // get list of unicodes that need glyph fallback + int nCharPos = -1; + bool bRTL = false; + OUStringBuffer aMissingCodeBuf; + while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) ) + aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] ); + rLayoutArgs.ResetPos(); + OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear(); + + FontSelectPattern aFontSelData = mpFontEntry->maFontSelData; + + // try if fallback fonts support the missing unicodes + for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel ) + { + // find a font family suited for glyph fallback +#ifndef FONTFALLBACK_HOOKS_DISABLED + // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry + // if the system-specific glyph fallback is active + aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level +#endif + ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontCollection, + aFontSelData, nFallbackLevel, aMissingCodes ); + if( !pFallbackFont ) + break; + + aFontSelData.mpFontEntry = pFallbackFont; + aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData; + if( mpFontEntry && nFallbackLevel < MAX_FALLBACK-1) + { + // ignore fallback font if it is the same as the original font + if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData ) + { + mpFontCache->Release( pFallbackFont ); + continue; + } + } + + // create and add glyph fallback layout to multilayout + SalLayout* pFallback = getFallbackFont(*pFallbackFont, aFontSelData, + nFallbackLevel, rLayoutArgs); + if (pFallback) + { + if( !pMultiSalLayout ) + pMultiSalLayout = new MultiSalLayout( *pSalLayout ); + pMultiSalLayout->AddFallback( *pFallback, + rLayoutArgs.maRuns, aFontSelData.mpFontData ); + if (nFallbackLevel == MAX_FALLBACK-1) + pMultiSalLayout->SetInComplete(); + } + + mpFontCache->Release( pFallbackFont ); + + // break when this fallback was sufficient + if( !rLayoutArgs.PrepareFallback() ) + break; + } + + if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) ) + pSalLayout = pMultiSalLayout; + + // restore orig font settings + pSalLayout->InitFont(); + rLayoutArgs.maRuns = aLayoutRuns; + + return pSalLayout; +} + +int OutputDevice::GetDevFontCount() const +{ + + if( !mpGetDevFontList ) + mpGetDevFontList = mpFontCollection->GetDevFontList(); + return mpGetDevFontList->Count(); +} + +FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const +{ + + FontInfo aFontInfo; + + ImplInitFontList(); + + int nCount = GetDevFontCount(); + if( nDevFontIndex < nCount ) + { + const PhysicalFontFace& rData = *mpGetDevFontList->Get( nDevFontIndex ); + aFontInfo.SetName( rData.GetFamilyName() ); + aFontInfo.SetStyleName( rData.GetStyleName() ); + aFontInfo.SetCharSet( rData.IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); + aFontInfo.SetFamily( rData.GetFamilyType() ); + aFontInfo.SetPitch( rData.GetPitch() ); + aFontInfo.SetWeight( rData.GetWeight() ); + aFontInfo.SetItalic( rData.GetSlant() ); + aFontInfo.SetWidthType( rData.GetWidthType() ); + if( rData.IsScalable() ) + aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG; + if( rData.mbDevice ) + aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG; + } + + return aFontInfo; +} + +bool OutputDevice::AddTempDevFont( const OUString& rFileURL, const OUString& rFontName ) +{ + + ImplInitFontList(); + + if( !mpGraphics && !ImplGetGraphics() ) + return false; + + bool bRC = mpGraphics->AddTempDevFont( mpFontCollection, rFileURL, rFontName ); + if( !bRC ) + return false; + + if( mpAlphaVDev ) + mpAlphaVDev->AddTempDevFont( rFileURL, rFontName ); + + mpFontCache->Invalidate(); + return true; +} + +int OutputDevice::GetDevFontSizeCount( const Font& rFont ) const +{ + + delete mpGetDevSizeList; + + ImplInitFontList(); + mpGetDevSizeList = mpFontCollection->GetDevSizeList( rFont.GetName() ); + return mpGetDevSizeList->Count(); +} + +Size OutputDevice::GetDevFontSize( const Font& rFont, int nSizeIndex ) const +{ + + // check range + int nCount = GetDevFontSizeCount( rFont ); + if ( nSizeIndex >= nCount ) + return Size(); + + // when mapping is enabled round to .5 points + Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) ); + if ( mbMap ) + { + aSize.Height() *= 10; + MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) ); + aSize = PixelToLogic( aSize, aMap ); + aSize.Height() += 5; + aSize.Height() /= 10; + long nRound = aSize.Height() % 5; + if ( nRound >= 3 ) + aSize.Height() += (5-nRound); + else + aSize.Height() -= nRound; + aSize.Height() *= 10; + aSize = LogicToPixel( aSize, aMap ); + aSize = PixelToLogic( aSize ); + aSize.Height() += 5; + aSize.Height() /= 10; + } + return aSize; +} + +bool OutputDevice::IsFontAvailable( const OUString& rFontName ) const +{ + + PhysicalFontFamily* pFound = mpFontCollection->FindFontFamily( rFontName ); + return (pFound != NULL); +} + +FontMetric OutputDevice::GetFontMetric() const +{ + + FontMetric aMetric; + if( mbNewFont && !ImplNewFont() ) + return aMetric; + + ImplFontEntry* pEntry = mpFontEntry; + ImplFontMetricData* pMetric = &(pEntry->maMetric); + + // prepare metric + aMetric.Font::operator=( maFont ); + + // set aMetric with info from font + aMetric.SetName( maFont.GetName() ); + aMetric.SetStyleName( pMetric->GetStyleName() ); + aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) ); + aMetric.SetCharSet( pMetric->IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); + aMetric.SetFamily( pMetric->GetFamilyType() ); + aMetric.SetPitch( pMetric->GetPitch() ); + aMetric.SetWeight( pMetric->GetWeight() ); + aMetric.SetItalic( pMetric->GetSlant() ); + aMetric.SetWidthType( pMetric->GetWidthType() ); + if ( pEntry->mnOwnOrientation ) + aMetric.SetOrientation( pEntry->mnOwnOrientation ); + else + aMetric.SetOrientation( pMetric->mnOrientation ); + if( !pEntry->maMetric.mbKernableFont ) + aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC ); + + // set remaining metric fields + aMetric.mpImplMetric->mnMiscFlags = 0; + if( pMetric->mbDevice ) + aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG; + if( pMetric->mbScalableFont ) + aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG; + aMetric.mpImplMetric->mnAscent = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent ); + aMetric.mpImplMetric->mnDescent = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent ); + aMetric.mpImplMetric->mnIntLeading = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent ); + aMetric.mpImplMetric->mnExtLeading = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading ); + aMetric.mpImplMetric->mnLineHeight = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent ); + aMetric.mpImplMetric->mnSlant = ImplDevicePixelToLogicHeight( pMetric->mnSlant ); + +#ifdef UNX + // backwards compatible line metrics after fixing #i60945# + if( (meOutDevType == OUTDEV_VIRDEV) + && static_cast<const VirtualDevice*>(this)->ForceZeroExtleadBug() ) + aMetric.mpImplMetric->mnExtLeading = 0; +#endif + + return aMetric; +} + +FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const +{ + // select font, query metrics, select original font again + Font aOldFont = GetFont(); + const_cast<OutputDevice*>(this)->SetFont( rFont ); + FontMetric aMetric( GetFontMetric() ); + const_cast<OutputDevice*>(this)->SetFont( aOldFont ); + return aMetric; +} + +/** OutputDevice::GetSysFontData + * + * @param nFallbacklevel Fallback font level (0 = best matching font) + * + * Retrieve detailed font information in platform independent structure + * + * @return SystemFontData + **/ +SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const +{ + SystemFontData aSysFontData; + aSysFontData.nSize = sizeof(aSysFontData); + + if (!mpGraphics) ImplGetGraphics(); + if (mpGraphics) aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel); + + return aSysFontData; +} + +long OutputDevice::GetMinKashida() const +{ + if( mbNewFont && !ImplNewFont() ) + return 0; + + ImplFontEntry* pEntry = mpFontEntry; + ImplFontMetricData* pMetric = &(pEntry->maMetric); + return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida ); +} + +sal_Int32 OutputDevice::ValidateKashidas ( const OUString& rTxt, + sal_Int32 nIdx, sal_Int32 nLen, + sal_Int32 nKashCount, + const sal_Int32* pKashidaPos, + sal_Int32* pKashidaPosDropped ) const +{ + // do layout + SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen ); + if( !pSalLayout ) + return 0; + sal_Int32 nDropped = 0; + for( int i = 0; i < nKashCount; ++i ) + { + if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] )) + { + pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ]; + ++nDropped; + } + } + pSalLayout->Release(); + return nDropped; +} + +bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr, + int nIndex, int nLen, int nBase, MetricVector& rVector ) +{ + + rVector.clear(); + + if(nLen == 0x0FFFF) + { + SAL_INFO("sal.rtl.xub", + "GetGlyphBoundRects Suspicious arguments nLen:" << nLen); + } + + if( nIndex >= rStr.getLength() ) + return false; + + if( nLen < 0 || nIndex + nLen >= rStr.getLength() ) + { + nLen = rStr.getLength() - nIndex; + } + + Rectangle aRect; + for( int i = 0; i < nLen; i++ ) + { + if( !GetTextBoundRect( aRect, rStr, nBase, nIndex + i, 1 ) ) + break; + aRect.Move( rOrigin.X(), rOrigin.Y() ); + rVector.push_back( aRect ); + } + + return (nLen == (int)rVector.size()); +} + +bool OutputDevice::GetFontCapabilities( FontCapabilities& rFontCapabilities ) const +{ + // we need a graphics + if( !mpGraphics && !ImplGetGraphics() ) + return false; + + if( mbNewFont ) + ImplNewFont(); + if( mbInitFont ) + ImplInitFont(); + if( !mpFontEntry ) + return false; + + return mpGraphics->GetImplFontCapabilities(rFontCapabilities); +} + +bool OutputDevice::GetFontCharMap( FontCharMap& rFontCharMap ) const +{ + rFontCharMap.Reset(); + + // we need a graphics + if( !mpGraphics && !ImplGetGraphics() ) + return false; + + if( mbNewFont ) + ImplNewFont(); + if( mbInitFont ) + ImplInitFont(); + if( !mpFontEntry ) + return false; + +#ifdef ENABLE_IFC_CACHE // a little font charmap cache helps considerably + static const int NMAXITEMS = 16; + static int nUsedItems = 0, nCurItem = 0; + + struct CharMapCacheItem { const PhysicalFontFace* mpFontData; FontCharMap maCharMap; }; + static CharMapCacheItem aCache[ NMAXITEMS ]; + + const PhysicalFontFace* pFontData = mpFontEntry->maFontSelData.mpFontData; + + int i; + for( i = nUsedItems; --i >= 0; ) + if( pFontData == aCache[i].mpFontData ) + break; + if( i >= 0 ) // found in cache + { + rFontCharMap.Reset( aCache[i].maCharMap.mpImpl ); + } + else // need to cache +#endif // ENABLE_IFC_CACHE + { + const ImplFontCharMap* pNewMap = mpGraphics->GetImplFontCharMap(); + rFontCharMap.Reset( pNewMap ); + +#ifdef ENABLE_IFC_CACHE + // manage cache round-robin and insert data + CharMapCacheItem& rItem = aCache[ nCurItem ]; + rItem.mpFontData = pFontData; + rItem.maCharMap.Reset( pNewMap ); + + if( ++nCurItem >= NMAXITEMS ) + nCurItem = 0; + + if( ++nUsedItems >= NMAXITEMS ) + nUsedItems = NMAXITEMS; +#endif // ENABLE_IFC_CACHE + } + + if( rFontCharMap.IsDefaultMap() ) + return false; + return true; +} + +sal_Int32 OutputDevice::HasGlyphs( const Font& rTempFont, const OUString& rStr, + sal_Int32 nIndex, sal_Int32 nLen ) const +{ + if( nIndex >= rStr.getLength() ) + return nIndex; + sal_Int32 nEnd; + if( nLen == -1 ) + nEnd = rStr.getLength(); + else + nEnd = std::min( rStr.getLength(), nIndex + nLen ); + + DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" ); + DBG_ASSERT( nEnd <= rStr.getLength(), "String too short" ); + + // to get the map temporarily set font + const Font aOrigFont = GetFont(); + const_cast<OutputDevice&>(*this).SetFont( rTempFont ); + FontCharMap aFontCharMap; + bool bRet = GetFontCharMap( aFontCharMap ); + const_cast<OutputDevice&>(*this).SetFont( aOrigFont ); + + // if fontmap is unknown assume it doesn't have the glyphs + if( !bRet ) + return nIndex; + + for( sal_Int32 i = nIndex; nIndex < nEnd; ++i, ++nIndex ) + if( ! aFontCharMap.HasChar( rStr[i] ) ) + return nIndex; + + return -1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/outdev3.cxx b/vcl/source/outdev/text.cxx index 08d71ce7c399..3bf4e3e88bbf 100644 --- a/vcl/source/outdev/outdev3.cxx +++ b/vcl/source/outdev/text.cxx @@ -81,12 +81,6 @@ #include "com/sun/star/linguistic2/LinguServiceManager.hpp" #include <comphelper/processfactory.hxx> -#if defined UNX -#define GLYPH_FONT_HEIGHT 128 -#else -#define GLYPH_FONT_HEIGHT 256 -#endif - #include "sal/alloca.h" #include <cmath> @@ -106,1009 +100,6 @@ using namespace ::utl; #define UNDERLINE_LAST UNDERLINE_BOLDWAVE #define STRIKEOUT_LAST STRIKEOUT_X -static void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY, - int nOrientation ) -{ - if ( (nOrientation >= 0) && !(nOrientation % 900) ) - { - if ( (nOrientation >= 3600) ) - nOrientation %= 3600; - - if ( nOrientation ) - { - rX -= nOriginX; - rY -= nOriginY; - - if ( nOrientation == 900 ) - { - long nTemp = rX; - rX = rY; - rY = -nTemp; - } - else if ( nOrientation == 1800 ) - { - rX = -rX; - rY = -rY; - } - else /* ( nOrientation == 2700 ) */ - { - long nTemp = rX; - rX = -rY; - rY = nTemp; - } - - rX += nOriginX; - rY += nOriginY; - } - } - else - { - double nRealOrientation = nOrientation*F_PI1800; - double nCos = cos( nRealOrientation ); - double nSin = sin( nRealOrientation ); - - // Translation... - long nX = rX-nOriginX; - long nY = rY-nOriginY; - - // Rotation... - rX = +((long)(nCos*nX + nSin*nY)) + nOriginX; - rY = -((long)(nSin*nX - nCos*nY)) + nOriginY; - } -} - -void OutputDevice::ImplClearFontData( const bool bNewFontLists ) -{ - // the currently selected logical font is no longer needed - if ( mpFontEntry ) - { - mpFontCache->Release( mpFontEntry ); - mpFontEntry = NULL; - } - - mbInitFont = true; - mbNewFont = true; - - if ( bNewFontLists ) - { - if ( mpGetDevFontList ) - { - delete mpGetDevFontList; - mpGetDevFontList = NULL; - } - if ( mpGetDevSizeList ) - { - delete mpGetDevSizeList; - mpGetDevSizeList = NULL; - } - - // release all physically selected fonts on this device - if( ImplGetGraphics() ) - mpGraphics->ReleaseFonts(); - } - -// if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter ) - { - ImplSVData* pSVData = ImplGetSVData(); - - if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache ) - mpFontCache->Invalidate(); - - if ( bNewFontLists ) - { - // we need a graphics - if ( ImplGetGraphics() ) - { - if( mpFontCollection && mpFontCollection != pSVData->maGDIData.mpScreenFontList ) - mpFontCollection->Clear(); - - if( mpPDFWriter ) - { - if( mpFontCollection && mpFontCollection != pSVData->maGDIData.mpScreenFontList ) - delete mpFontCollection; - if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache ) - delete mpFontCache; - mpFontCollection = 0; - mpFontCache = 0; - } - } - } - } - - // also update child windows if needed - if ( GetOutDevType() == OUTDEV_WINDOW ) - { - Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild; - while ( pChild ) - { - pChild->ImplClearFontData( true ); - pChild = pChild->mpWindowImpl->mpNext; - } - } -} - -void OutputDevice::ImplRefreshFontData( const bool bNewFontLists ) -{ -// if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter ) - { - ImplSVData* pSVData = ImplGetSVData(); - - if ( bNewFontLists ) - { - // we need a graphics - if ( ImplGetGraphics() ) - { - if( mpPDFWriter ) - { - mpFontCollection = pSVData->maGDIData.mpScreenFontList->Clone( true, true ); - mpFontCache = new ImplFontCache(); - } - else - { - mpGraphics->GetDevFontList( mpFontCollection ); - } - } - } - } - - // also update child windows if needed - if ( GetOutDevType() == OUTDEV_WINDOW ) - { - Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild; - while ( pChild ) - { - pChild->ImplRefreshFontData( true ); - pChild = pChild->mpWindowImpl->mpNext; - } - } -} - -void OutputDevice::ImplUpdateFontData( bool bNewFontLists ) -{ - ImplClearFontData( bNewFontLists ); - ImplRefreshFontData( bNewFontLists ); -} - -void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists ) -{ - ImplSVData* pSVData = ImplGetSVData(); - - ImplUpdateFontDataForAllFrames( &OutputDevice::ImplClearFontData, bNewFontLists ); - - // clear global font lists to have them updated - pSVData->maGDIData.mpScreenFontCache->Invalidate(); - if ( bNewFontLists ) - { - pSVData->maGDIData.mpScreenFontList->Clear(); - Window * pFrame = pSVData->maWinData.mpFirstFrame; - if ( pFrame ) - { - if ( pFrame->ImplGetGraphics() ) - { - // Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler - OutputDevice *pDevice = (OutputDevice*)pFrame; - pDevice->mpGraphics->ClearDevFontCache(); - pDevice->mpGraphics->GetDevFontList(pFrame->mpWindowImpl->mpFrameData->mpFontCollection); - } - } - } - - ImplUpdateFontDataForAllFrames( &OutputDevice::ImplRefreshFontData, bNewFontLists ); -} - -void OutputDevice::ImplUpdateFontDataForAllFrames( const FontUpdateHandler_t pHdl, const bool bNewFontLists ) -{ - ImplSVData* const pSVData = ImplGetSVData(); - - // update all windows - Window* pFrame = pSVData->maWinData.mpFirstFrame; - while ( pFrame ) - { - ( pFrame->*pHdl )( bNewFontLists ); - - Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap; - while ( pSysWin ) - { - ( pSysWin->*pHdl )( bNewFontLists ); - pSysWin = pSysWin->mpWindowImpl->mpNextOverlap; - } - - pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame; - } - - // update all virtual devices - VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev; - while ( pVirDev ) - { - ( pVirDev->*pHdl )( bNewFontLists ); - pVirDev = pVirDev->mpNext; - } - - // update all printers - Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter; - while ( pPrinter ) - { - ( pPrinter->*pHdl )( bNewFontLists ); - pPrinter = pPrinter->mpNext; - } -} - -void OutputDevice::BeginFontSubstitution() -{ - ImplSVData* pSVData = ImplGetSVData(); - pSVData->maGDIData.mbFontSubChanged = false; -} - -void OutputDevice::EndFontSubstitution() -{ - ImplSVData* pSVData = ImplGetSVData(); - if ( pSVData->maGDIData.mbFontSubChanged ) - { - ImplUpdateAllFontData( false ); - - Application* pApp = GetpApp(); - DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION ); - pApp->DataChanged( aDCEvt ); - pApp->NotifyAllWindows( aDCEvt ); - pSVData->maGDIData.mbFontSubChanged = false; - } -} - -void OutputDevice::AddFontSubstitute( const OUString& rFontName, - const OUString& rReplaceFontName, - sal_uInt16 nFlags ) -{ - ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; - if( !rpSubst ) - rpSubst = new ImplDirectFontSubstitution(); - rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags ); - ImplGetSVData()->maGDIData.mbFontSubChanged = true; -} - -void ImplDirectFontSubstitution::AddFontSubstitute( const OUString& rFontName, - const OUString& rSubstFontName, sal_uInt16 nFlags ) -{ - maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) ); -} - -ImplFontSubstEntry::ImplFontSubstEntry( const OUString& rFontName, - const OUString& rSubstFontName, sal_uInt16 nSubstFlags ) -: maName( rFontName ) -, maReplaceName( rSubstFontName ) -, mnFlags( nSubstFlags ) -{ - maSearchName = rFontName; - maSearchReplaceName = rSubstFontName; - GetEnglishSearchFontName( maSearchName ); - GetEnglishSearchFontName( maSearchReplaceName ); -} - -void OutputDevice::RemoveFontSubstitute( sal_uInt16 n ) -{ - ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; - if( pSubst ) - pSubst->RemoveFontSubstitute( n ); -} - -void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex ) -{ - FontSubstList::iterator it = maFontSubstList.begin(); - for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ; - if( it != maFontSubstList.end() ) - maFontSubstList.erase( it ); -} - -sal_uInt16 OutputDevice::GetFontSubstituteCount() -{ - const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; - if( !pSubst ) - return 0; - int nCount = pSubst->GetFontSubstituteCount(); - return (sal_uInt16)nCount; -} - -bool ImplDirectFontSubstitution::FindFontSubstitute( OUString& rSubstName, - const OUString& rSearchName, sal_uInt16 nFlags ) const -{ - // TODO: get rid of O(N) searches - FontSubstList::const_iterator it = maFontSubstList.begin(); - for(; it != maFontSubstList.end(); ++it ) - { - const ImplFontSubstEntry& rEntry = *it; - if( ((rEntry.mnFlags & nFlags) || !nFlags) - && (rEntry.maSearchName == rSearchName) ) - { - rSubstName = rEntry.maSearchReplaceName; - return true; - } - } - - return false; -} - -void ImplFontSubstitute( OUString& rFontName ) -{ -#ifdef DBG_UTIL - OUString aTempName = rFontName; - GetEnglishSearchFontName( aTempName ); - DBG_ASSERT( aTempName == rFontName, "ImplFontSubstitute() called without a searchname" ); -#endif - - OUString aSubstFontName; - - // apply user-configurable font replacement (eg, from the list in Tools->Options) - const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; - if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) ) - { - rFontName = aSubstFontName; - return; - } -} - -//hidpi TODO: This routine has hard-coded font-sizes that break places such as DialControl -Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang, - sal_uLong nFlags, const OutputDevice* pOutDev ) -{ - if (!pOutDev) // default is NULL - pOutDev = Application::GetDefaultDevice(); - - LanguageTag aLanguageTag( - ( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW ) ? - Application::GetSettings().GetUILanguageTag() : - LanguageTag( eLang )); - - utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get(); - OUString aDefault = rDefaults.getDefaultFont( aLanguageTag, nType ); - OUString aSearch; - - if( !aDefault.isEmpty() ) - aSearch = aDefault; - else - aSearch = rDefaults.getUserInterfaceFont( aLanguageTag ); // use the UI font as a fallback - - Font aFont; - aFont.SetPitch( PITCH_VARIABLE ); - - switch ( nType ) - { - case DEFAULTFONT_SANS_UNICODE: - case DEFAULTFONT_UI_SANS: - aFont.SetFamily( FAMILY_SWISS ); - break; - - case DEFAULTFONT_SANS: - case DEFAULTFONT_LATIN_HEADING: - case DEFAULTFONT_LATIN_SPREADSHEET: - case DEFAULTFONT_LATIN_DISPLAY: - aFont.SetFamily( FAMILY_SWISS ); - break; - - case DEFAULTFONT_SERIF: - case DEFAULTFONT_LATIN_TEXT: - case DEFAULTFONT_LATIN_PRESENTATION: - aFont.SetFamily( FAMILY_ROMAN ); - break; - - case DEFAULTFONT_FIXED: - case DEFAULTFONT_LATIN_FIXED: - case DEFAULTFONT_UI_FIXED: - aFont.SetPitch( PITCH_FIXED ); - aFont.SetFamily( FAMILY_MODERN ); - break; - - case DEFAULTFONT_SYMBOL: - aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL ); - break; - - case DEFAULTFONT_CJK_TEXT: - case DEFAULTFONT_CJK_PRESENTATION: - case DEFAULTFONT_CJK_SPREADSHEET: - case DEFAULTFONT_CJK_HEADING: - case DEFAULTFONT_CJK_DISPLAY: - aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later... - break; - - case DEFAULTFONT_CTL_TEXT: - case DEFAULTFONT_CTL_PRESENTATION: - case DEFAULTFONT_CTL_SPREADSHEET: - case DEFAULTFONT_CTL_HEADING: - case DEFAULTFONT_CTL_DISPLAY: - aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later... - break; - } - - if ( !aSearch.isEmpty() ) - { - aFont.SetHeight( 12 ); // corresponds to nDefaultHeight - aFont.SetWeight( WEIGHT_NORMAL ); - aFont.SetLanguage( eLang ); - - if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW ) - aFont.SetCharSet( osl_getThreadTextEncoding() ); - - // Should we only return available fonts on the given device - if ( pOutDev ) - { - pOutDev->ImplInitFontList(); - - // Search Font in the FontList - OUString aName; - OUString aSearchName; - sal_Int32 nIndex = 0; - do - { - aSearchName = GetNextFontToken( aSearch, nIndex ); - GetEnglishSearchFontName( aSearchName ); - PhysicalFontFamily* pFontFamily = pOutDev->mpFontCollection->ImplFindBySearchName( aSearchName ); - if( pFontFamily ) - { - AddTokenFontName( aName, pFontFamily->GetFamilyName() ); - if( nFlags & DEFAULTFONT_FLAGS_ONLYONE ) - break; - } - } - while ( nIndex != -1 ); - aFont.SetName( aName ); - } - - // No Name, than set all names - if ( aFont.GetName().isEmpty() ) - { - if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE ) - { - if( !pOutDev ) - { - SAL_WARN ("vcl.gdi", "No default window has been set for the application - we really shouldn't be able to get here"); - sal_Int32 nIndex = 0; - aFont.SetName( aSearch.getToken( 0, ';', nIndex ) ); - } - else - { - pOutDev->ImplInitFontList(); - - aFont.SetName( aSearch ); - - // convert to pixel height - Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() ); - if ( !aSize.Height() ) - { - // use default pixel height only when logical height is zero - if ( aFont.GetHeight() ) - aSize.Height() = 1; - else - aSize.Height() = (12*pOutDev->mnDPIY)/72; - } - - // use default width only when logical width is zero - if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) ) - aSize.Width() = 1; - - // get the name of the first available font - float fExactHeight = static_cast<float>(aSize.Height()); - ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontCollection, aFont, aSize, fExactHeight ); - if (pEntry) - { - if( pEntry->maFontSelData.mpFontData ) - aFont.SetName( pEntry->maFontSelData.mpFontData->GetFamilyName() ); - else - aFont.SetName( pEntry->maFontSelData.maTargetName ); - } - } - } - else - aFont.SetName( aSearch ); - } - } - -#if OSL_DEBUG_LEVEL > 2 - const char* s = "DEFAULTFONT_SANS_UNKNOWN"; - switch ( nType ) - { - case DEFAULTFONT_SANS_UNICODE: s = "DEFAULTFONT_SANS_UNICODE"; break; - case DEFAULTFONT_UI_SANS: s = "DEFAULTFONT_UI_SANS"; break; - - case DEFAULTFONT_SANS: s = "DEFAULTFONT_SANS"; break; - case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break; - case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break; - case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break; - - case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break; - case DEFAULTFONT_LATIN_TEXT: s = "DEFAULTFONT_LATIN_TEXT"; break; - case DEFAULTFONT_LATIN_PRESENTATION: s = "DEFAULTFONT_LATIN_PRESENTATION"; break; - - case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break; - case DEFAULTFONT_LATIN_FIXED: s = "DEFAULTFONT_LATIN_FIXED"; break; - case DEFAULTFONT_UI_FIXED: s = "DEFAULTFONT_UI_FIXED"; break; - - case DEFAULTFONT_SYMBOL: s = "DEFAULTFONT_SYMBOL"; break; - - case DEFAULTFONT_CJK_TEXT: s = "DEFAULTFONT_CJK_TEXT"; break; - case DEFAULTFONT_CJK_PRESENTATION: s = "DEFAULTFONT_CJK_PRESENTATION"; break; - case DEFAULTFONT_CJK_SPREADSHEET: s = "DEFAULTFONT_CJK_SPREADSHEET"; break; - case DEFAULTFONT_CJK_HEADING: s = "DEFAULTFONT_CJK_HEADING"; break; - case DEFAULTFONT_CJK_DISPLAY: s = "DEFAULTFONT_CJK_DISPLAY"; break; - - case DEFAULTFONT_CTL_TEXT: s = "DEFAULTFONT_CTL_TEXT"; break; - case DEFAULTFONT_CTL_PRESENTATION: s = "DEFAULTFONT_CTL_PRESENTATION"; break; - case DEFAULTFONT_CTL_SPREADSHEET: s = "DEFAULTFONT_CTL_SPREADSHEET"; break; - case DEFAULTFONT_CTL_HEADING: s = "DEFAULTFONT_CTL_HEADING"; break; - case DEFAULTFONT_CTL_DISPLAY: s = "DEFAULTFONT_CTL_DISPLAY"; break; - } - fprintf( stderr, " OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n", - s, eLang, nFlags, - OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr() - ); -#endif - - return aFont; -} - -ImplFontEntry::ImplFontEntry( const FontSelectPattern& rFontSelData ) - : maFontSelData( rFontSelData ) - , maMetric( rFontSelData ) - , mpConversion( NULL ) - , mnLineHeight( 0 ) - , mnRefCount( 1 ) - , mnSetFontFlags( 0 ) - , mnOwnOrientation( 0 ) - , mnOrientation( 0 ) - , mbInit( false ) - , mpUnicodeFallbackList( NULL ) -{ - maFontSelData.mpFontEntry = this; -} - -ImplFontEntry::~ImplFontEntry() -{ - delete mpUnicodeFallbackList; -} - -size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const -{ - boost::hash<sal_UCS4> a; - boost::hash<int > b; - return a(rData.first) ^ b(rData.second); -} - -void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName ) -{ - if( !mpUnicodeFallbackList ) - mpUnicodeFallbackList = new UnicodeFallbackList; - (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName; -} - -bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, OUString* pFontName ) const -{ - if( !mpUnicodeFallbackList ) - return false; - - UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) ); - if( it == mpUnicodeFallbackList->end() ) - return false; - - *pFontName = (*it).second; - return true; -} - -void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName ) -{ -// DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" ); - UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) ); -// DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" ); - if( it == mpUnicodeFallbackList->end() ) - return; - if( (*it).second == rFontName ) - mpUnicodeFallbackList->erase( it ); -} - -FontSelectPatternAttributes::FontSelectPatternAttributes( const Font& rFont, - const OUString& rSearchName, const Size& rSize, float fExactHeight ) - : maSearchName( rSearchName ) - , mnWidth( rSize.Width() ) - , mnHeight( rSize.Height() ) - , mfExactHeight( fExactHeight) - , mnOrientation( rFont.GetOrientation() ) - , meLanguage( rFont.GetLanguage() ) - , mbVertical( rFont.IsVertical() ) - , mbNonAntialiased( false ) - , mbEmbolden( false ) -{ - maTargetName = GetFamilyName(); - - rFont.GetFontAttributes( *this ); - - // normalize orientation between 0 and 3600 - if( 3600 <= (unsigned)mnOrientation ) - { - if( mnOrientation >= 0 ) - mnOrientation %= 3600; - else - mnOrientation = 3600 - (-mnOrientation % 3600); - } - - // normalize width and height - if( mnHeight < 0 ) - mnHeight = -mnHeight; - if( mnWidth < 0 ) - mnWidth = -mnWidth; -} - -FontSelectPattern::FontSelectPattern( const Font& rFont, - const OUString& rSearchName, const Size& rSize, float fExactHeight) - : FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight) - , mpFontData( NULL ) - , mpFontEntry( NULL ) -{ -} - -// NOTE: this ctor is still used on Windows. Do not remove. -#ifdef WNT -FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData, - const Size& rSize, float fExactHeight, int nOrientation, bool bVertical ) - : ImplFontAttributes( rFontData ) - , mnWidth( rSize.Width() ) - , mnHeight( rSize.Height() ) - , mfExactHeight( fExactHeight ) - , mnOrientation( nOrientation ) - , meLanguage( 0 ) - , mbVertical( bVertical ) - , mbNonAntialiased( false ) - , mbEmbolden( false ) -{ - maTargetName = maSearchName = GetFamilyName(); - // NOTE: no normalization for width/height/orientation -} - -FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData, - const Size& rSize, float fExactHeight, int nOrientation, bool bVertical ) - : FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical) - , mpFontData( &rFontData ) - , mpFontEntry( NULL ) -{ -} -#endif - -void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes) -{ - static_cast<FontSelectPatternAttributes&>(*this) = rAttributes; -} - -size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const -{ - return rFSD.hashCode(); -} - -size_t FontSelectPatternAttributes::hashCode() const -{ - // TODO: does it pay off to improve this hash function? - static FontNameHash aFontNameHash; - size_t nHash = aFontNameHash( maSearchName ); -#if ENABLE_GRAPHITE - // check for features and generate a unique hash if necessary - if (maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) - != -1) - { - nHash = aFontNameHash( maTargetName ); - } -#endif - nHash += 11 * mnHeight; - nHash += 19 * GetWeight(); - nHash += 29 * GetSlant(); - nHash += 37 * mnOrientation; - nHash += 41 * meLanguage; - if( mbVertical ) - nHash += 53; - return nHash; -} - -bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const -{ - if (static_cast<const ImplFontAttributes&>(*this) != static_cast<const ImplFontAttributes&>(rOther)) - return false; - - if (maTargetName != rOther.maTargetName) - return false; - - if (maSearchName != rOther.maSearchName) - return false; - - if (mnWidth != rOther.mnWidth) - return false; - - if (mnHeight != rOther.mnHeight) - return false; - - if (mfExactHeight != rOther.mfExactHeight) - return false; - - if (mnOrientation != rOther.mnOrientation) - return false; - - if (meLanguage != rOther.meLanguage) - return false; - - if (mbVertical != rOther.mbVertical) - return false; - - if (mbNonAntialiased != rOther.mbNonAntialiased) - return false; - - if (mbEmbolden != rOther.mbEmbolden) - return false; - - if (maItalicMatrix != rOther.maItalicMatrix) - return false; - - return true; -} - -bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const -{ - // check normalized font family name - if( rA.maSearchName != rB.maSearchName ) - return false; - - // check font transformation - if( (rA.mnHeight != rB.mnHeight) - || (rA.mnWidth != rB.mnWidth) - || (rA.mnOrientation != rB.mnOrientation) ) - return false; - - // check mapping relevant attributes - if( (rA.mbVertical != rB.mbVertical) - || (rA.meLanguage != rB.meLanguage) ) - return false; - - // check font face attributes - if( (rA.GetWeight() != rB.GetWeight()) - || (rA.GetSlant() != rB.GetSlant()) -// || (rA.meFamily != rB.meFamily) // TODO: remove this mostly obsolete member - || (rA.GetPitch() != rB.GetPitch()) ) - return false; - - // check style name - if( rA.GetStyleName() != rB.GetStyleName() ) - return false; - - // Symbol fonts may recode from one type to another So they are only - // safely equivalent for equal targets - if ( - (rA.mpFontData && rA.mpFontData->IsSymbolFont()) || - (rB.mpFontData && rB.mpFontData->IsSymbolFont()) - ) - { - if (rA.maTargetName != rB.maTargetName) - return false; - } - -#if ENABLE_GRAPHITE - // check for features - if ((rA.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) - != -1 || - rB.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) - != -1) && rA.maTargetName != rB.maTargetName) - return false; -#endif - - if (rA.mbEmbolden != rB.mbEmbolden) - return false; - - if (rA.maItalicMatrix != rB.maItalicMatrix) - return false; - - return true; -} - -ImplFontCache::ImplFontCache() -: mpFirstEntry( NULL ), - mnRef0Count( 0 ) -{} - -ImplFontCache::~ImplFontCache() -{ - FontInstanceList::iterator it = maFontInstanceList.begin(); - for(; it != maFontInstanceList.end(); ++it ) - { - ImplFontEntry* pEntry = (*it).second; - delete pEntry; - } -} - -ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList, - const Font& rFont, const Size& rSize, float fExactHeight ) -{ - OUString aSearchName = rFont.GetName(); - - // initialize internal font request object - FontSelectPattern aFontSelData( rFont, aSearchName, rSize, fExactHeight ); - return GetFontEntry( pFontList, aFontSelData ); -} - -ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList, - FontSelectPattern& aFontSelData ) -{ - // check if a directly matching logical font instance is already cached, - // the most recently used font usually has a hit rate of >50% - ImplFontEntry *pEntry = NULL; - PhysicalFontFamily* pFontFamily = NULL; - IFSD_Equal aIFSD_Equal; - if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) ) - pEntry = mpFirstEntry; - else - { - FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData ); - if( it != maFontInstanceList.end() ) - pEntry = (*it).second; - } - - if( !pEntry ) // no direct cache hit - { - // find the best matching logical font family and update font selector accordingly - pFontFamily = pFontList->ImplFindByFont( aFontSelData ); - DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" ); - if( pFontFamily ) - aFontSelData.maSearchName = pFontFamily->GetSearchName(); - - // check if an indirectly matching logical font instance is already cached - FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData ); - if( it != maFontInstanceList.end() ) - { - // we have an indirect cache hit - pEntry = (*it).second; - } - } - - PhysicalFontFace* pFontData = NULL; - - if (!pEntry && pFontFamily)// no cache hit => find the best matching physical font face - { - bool bOrigWasSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont(); - pFontData = pFontFamily->FindBestFontFace( aFontSelData ); - aFontSelData.mpFontData = pFontData; - bool bNewIsSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont(); - - if (bNewIsSymbol != bOrigWasSymbol) - { - // it is possible, though generally unlikely, that at this point we - // will attempt to use a symbol font as a last-ditch fallback for a - // non-symbol font request or vice versa, and by changing - // aFontSelData.mpFontData to/from a symbol font we may now find - // something in the cache that can be reused which previously - // wasn't a candidate - FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData ); - if( it != maFontInstanceList.end() ) - pEntry = (*it).second; - } - } - - if( pEntry ) // cache hit => use existing font instance - { - // increase the font instance's reference count - if( !pEntry->mnRefCount++ ) - --mnRef0Count; - } - - if (!pEntry && pFontData)// still no cache hit => create a new font instance - { - // create a new logical font instance from this physical font face - pEntry = pFontData->CreateFontInstance( aFontSelData ); - - // if we're subtituting from or to a symbol font we may need a symbol - // conversion table - if( pFontData->IsSymbolFont() || aFontSelData.IsSymbolFont() ) - { - if( aFontSelData.maTargetName != aFontSelData.maSearchName ) - pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName ); - } - -#ifdef MACOSX - //It might be better to dig out the font version of the target font - //to see if it's a modern re-coded apple symbol font in case that - //font shows up on a different platform - if (!pEntry->mpConversion && - aFontSelData.maTargetName.equalsIgnoreAsciiCase("symbol") && - aFontSelData.maSearchName.equalsIgnoreAsciiCase("symbol")) - { - pEntry->mpConversion = ConvertChar::GetRecodeData( OUString("Symbol"), OUString("AppleSymbol") ); - } -#endif - - // add the new entry to the cache - maFontInstanceList[ aFontSelData ] = pEntry; - } - - mpFirstEntry = pEntry; - return pEntry; -} - -ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( PhysicalFontCollection* pFontCollection, - FontSelectPattern& rFontSelData, int nFallbackLevel, OUString& rMissingCodes ) -{ - // get a candidate font for glyph fallback - // unless the previously selected font got a device specific substitution - // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it - if( nFallbackLevel >= 1) - { - PhysicalFontFamily* pFallbackData = NULL; - - //fdo#33898 If someone has EUDC installed then they really want that to - //be used as the first-choice glyph fallback seeing as it's filled with - //private area codes with don't make any sense in any other font so - //prioritise it here if it's available. Ideally we would remove from - //rMissingCodes all the glyphs which it is able to resolve as an - //optimization, but that's tricky to achieve cross-platform without - //sufficient heavy-weight code that's likely to undo the value of the - //optimization - if (nFallbackLevel == 1) - pFallbackData = pFontCollection->FindFontFamily(OUString("EUDC")); - if (!pFallbackData) - pFallbackData = pFontCollection->GetGlyphFallbackFont(rFontSelData, rMissingCodes, nFallbackLevel-1); - // escape when there are no font candidates - if( !pFallbackData ) - return NULL; - // override the font name - rFontSelData.SetFamilyName( pFallbackData->GetFamilyName() ); - // clear the cached normalized name - rFontSelData.maSearchName = ""; - } - - ImplFontEntry* pFallbackFont = GetFontEntry( pFontCollection, rFontSelData ); - return pFallbackFont; -} - -void ImplFontCache::Release( ImplFontEntry* pEntry ) -{ - static const int FONTCACHE_MAX = 50; - - DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" ); - if( --pEntry->mnRefCount > 0 ) - return; - - if( ++mnRef0Count < FONTCACHE_MAX ) - return; - - // remove unused entries from font instance cache - FontInstanceList::iterator it_next = maFontInstanceList.begin(); - while( it_next != maFontInstanceList.end() ) - { - FontInstanceList::iterator it = it_next++; - ImplFontEntry* pFontEntry = (*it).second; - if( pFontEntry->mnRefCount > 0 ) - continue; - - maFontInstanceList.erase( it ); - delete pFontEntry; - --mnRef0Count; - DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" ); - - if( mpFirstEntry == pFontEntry ) - mpFirstEntry = NULL; - } - - DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" ); -} - -void ImplFontCache::Invalidate() -{ - // delete unreferenced entries - FontInstanceList::iterator it = maFontInstanceList.begin(); - for(; it != maFontInstanceList.end(); ++it ) - { - ImplFontEntry* pFontEntry = (*it).second; - if( pFontEntry->mnRefCount > 0 ) - continue; - - delete pFontEntry; - --mnRef0Count; - } - - // #112304# make sure the font cache is really clean - mpFirstEntry = NULL; - maFontInstanceList.clear(); - - DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" ); -} - ImplMultiTextLineInfo::ImplMultiTextLineInfo() { mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE]; @@ -1144,32 +135,6 @@ void ImplMultiTextLineInfo::Clear() mnLines = 0; } -FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const Font& rFont ) -{ - FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark(); - - // If no Position is set, then calculate the default position, which - // depends on the language - if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) ) - { - LanguageType eLang = rFont.GetLanguage(); - // In Chinese Simplified the EmphasisMarks are below/left - if (MsLangId::isSimplifiedChinese(eLang)) - nEmphasisMark |= EMPHASISMARK_POS_BELOW; - else - { - eLang = rFont.GetCJKContextLanguage(); - // In Chinese Simplified the EmphasisMarks are below/left - if (MsLangId::isSimplifiedChinese(eLang)) - nEmphasisMark |= EMPHASISMARK_POS_BELOW; - else - nEmphasisMark |= EMPHASISMARK_POS_ABOVE; - } - } - - return nEmphasisMark; -} - bool OutputDevice::ImplIsUnderlineAbove( const Font& rFont ) { if ( !rFont.IsVertical() ) @@ -1183,57 +148,6 @@ bool OutputDevice::ImplIsUnderlineAbove( const Font& rFont ) return false; } -void OutputDevice::ImplInitFontList() const -{ - if( !mpFontCollection->Count() ) - { - if( mpGraphics || ImplGetGraphics() ) - { - SAL_INFO( "vcl.gdi", "OutputDevice::ImplInitFontList()" ); - mpGraphics->GetDevFontList( mpFontCollection ); - - // There is absolutely no way there should be no fonts available on the device - if( !mpFontCollection->Count() ) - { - OUString aError( "Application error: no fonts and no vcl resource found on your system" ); - ResMgr* pMgr = ImplGetResMgr(); - if( pMgr ) - { - OUString aResStr(ResId(SV_ACCESSERROR_NO_FONTS, *pMgr).toString()); - if( !aResStr.isEmpty() ) - aError = aResStr; - } - Application::Abort( aError ); - } - } - } -} - -void OutputDevice::ImplInitFont() const -{ - DBG_TESTSOLARMUTEX(); - - if (!mpFontEntry) - return; - - if ( mbInitFont ) - { - if ( meOutDevType != OUTDEV_PRINTER ) - { - // decide if antialiasing is appropriate - bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0; - const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); - bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0); - bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight); - mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased; - } - - // select font in the device layers - mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 ); - mbInitFont = false; - } -} - void OutputDevice::ImplInitTextColor() { DBG_TESTSOLARMUTEX(); @@ -1245,169 +159,6 @@ void OutputDevice::ImplInitTextColor() } } -bool OutputDevice::ImplNewFont() const -{ - DBG_TESTSOLARMUTEX(); - - // get correct font list on the PDF writer if necessary - if( mpPDFWriter ) - { - const ImplSVData* pSVData = ImplGetSVData(); - if( mpFontCollection == pSVData->maGDIData.mpScreenFontList - || mpFontCache == pSVData->maGDIData.mpScreenFontCache ) - const_cast<OutputDevice&>(*this).ImplUpdateFontData( true ); - } - - if ( !mbNewFont ) - return true; - - // we need a graphics - if ( !mpGraphics && !ImplGetGraphics() ) - return false; - SalGraphics* pGraphics = mpGraphics; - ImplInitFontList(); - - // convert to pixel height - // TODO: replace integer based aSize completely with subpixel accurate type - float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) ); - Size aSize = ImplLogicToDevicePixel( maFont.GetSize() ); - if ( !aSize.Height() ) - { - // use default pixel height only when logical height is zero - if ( maFont.GetSize().Height() ) - aSize.Height() = 1; - else - aSize.Height() = (12*mnDPIY)/72; - fExactHeight = static_cast<float>(aSize.Height()); - } - - // select the default width only when logical width is zero - if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) ) - aSize.Width() = 1; - - // get font entry - ImplFontEntry* pOldEntry = mpFontEntry; - mpFontEntry = mpFontCache->GetFontEntry( mpFontCollection, maFont, aSize, fExactHeight ); - if( pOldEntry ) - mpFontCache->Release( pOldEntry ); - - ImplFontEntry* pFontEntry = mpFontEntry; - - if (!pFontEntry) - return false; - - // mark when lower layers need to get involved - mbNewFont = false; - if( pFontEntry != pOldEntry ) - mbInitFont = true; - - // select font when it has not been initialized yet - if ( !pFontEntry->mbInit ) - { - ImplInitFont(); - - // get metric data from device layers - if ( pGraphics ) - { - pFontEntry->mbInit = true; - - pFontEntry->maMetric.mnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation); - pGraphics->GetFontMetric( &(pFontEntry->maMetric) ); - - pFontEntry->maMetric.ImplInitTextLineSize( this ); - pFontEntry->maMetric.ImplInitAboveTextLineSize(); - - pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent; - - if( pFontEntry->maFontSelData.mnOrientation - && !pFontEntry->maMetric.mnOrientation - && (meOutDevType != OUTDEV_PRINTER) ) - { - pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation); - pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation; - } - else - pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation; - } - } - - // enable kerning array if requested - if ( maFont.GetKerning() & KERNING_FONTSPECIFIC ) - { - // TODO: test if physical font supports kerning and disable if not - if( pFontEntry->maMetric.mbKernableFont ) - mbKerning = true; - } - else - mbKerning = false; - if ( maFont.GetKerning() & KERNING_ASIAN ) - mbKerning = true; - - // calculate EmphasisArea - mnEmphasisAscent = 0; - mnEmphasisDescent = 0; - if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE ) - { - FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont ); - long nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000; - if ( nEmphasisHeight < 1 ) - nEmphasisHeight = 1; - if ( nEmphasisMark & EMPHASISMARK_POS_BELOW ) - mnEmphasisDescent = nEmphasisHeight; - else - mnEmphasisAscent = nEmphasisHeight; - } - - // calculate text offset depending on TextAlignment - TextAlign eAlign = maFont.GetAlign(); - if ( eAlign == ALIGN_BASELINE ) - { - mnTextOffX = 0; - mnTextOffY = 0; - } - else if ( eAlign == ALIGN_TOP ) - { - mnTextOffX = 0; - mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent; - if ( pFontEntry->mnOrientation ) - ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation ); - } - else // eAlign == ALIGN_BOTTOM - { - mnTextOffX = 0; - mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent; - if ( pFontEntry->mnOrientation ) - ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation ); - } - - mbTextLines = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) || - ((maFont.GetOverline() != UNDERLINE_NONE) && (maFont.GetOverline() != UNDERLINE_DONTKNOW)) || - ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW)); - mbTextSpecial = maFont.IsShadow() || maFont.IsOutline() || - (maFont.GetRelief() != RELIEF_NONE); - - // #95414# fix for OLE objects which use scale factors very creatively - if( mbMap && !aSize.Width() ) - { - int nOrigWidth = pFontEntry->maMetric.mnWidth; - float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY; - fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX; - int nNewWidth = (int)(nOrigWidth * fStretch + 0.5); - if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) ) - { - Size aOrigSize = maFont.GetSize(); - const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) ); - mbMap = false; - mbNewFont = true; - ImplNewFont(); // recurse once using stretched width - mbMap = true; - const_cast<Font&>(maFont).SetSize( aOrigSize ); - } - } - - return true; -} - void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY, long nDistX, long nDistY, long nWidth, long nHeight ) { @@ -1532,223 +283,6 @@ void OutputDevice::ImplInitAboveTextLineSize() mpFontEntry->maMetric.ImplInitAboveTextLineSize(); } -bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const -{ - if (maName != rOther.maName) - return false; - - if (maStyleName != rOther.maStyleName) - return false; - - if (meWeight != rOther.meWeight) - return false; - - if (meItalic != rOther.meItalic) - return false; - - if (meFamily != rOther.meFamily) - return false; - - if (mePitch != rOther.mePitch) - return false; - - if (meWidthType != rOther.meWidthType) - return false; - - if (mbSymbolFlag != rOther.mbSymbolFlag) - return false; - - return true; -} - -ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData ) - : ImplFontAttributes( rFontSelData ) - , mnWidth ( rFontSelData.mnWidth) - , mnOrientation( (short)(rFontSelData.mnOrientation)) - , mnAscent( 0 ) - , mnDescent( 0 ) - , mnIntLeading( 0 ) - , mnExtLeading( 0 ) - , mnSlant( 0 ) - , mnMinKashida( 0 ) - , mnUnderlineSize( 0 ) - , mnUnderlineOffset( 0 ) - , mnBUnderlineSize( 0 ) - , mnBUnderlineOffset( 0 ) - , mnDUnderlineSize( 0 ) - , mnDUnderlineOffset1( 0 ) - , mnDUnderlineOffset2( 0 ) - , mnWUnderlineSize( 0 ) - , mnWUnderlineOffset( 0 ) - , mnAboveUnderlineSize( 0 ) - , mnAboveUnderlineOffset( 0 ) - , mnAboveBUnderlineSize( 0 ) - , mnAboveBUnderlineOffset( 0 ) - , mnAboveDUnderlineSize( 0 ) - , mnAboveDUnderlineOffset1( 0 ) - , mnAboveDUnderlineOffset2( 0 ) - , mnAboveWUnderlineSize( 0 ) - , mnAboveWUnderlineOffset( 0 ) - , mnStrikeoutSize( 0 ) - , mnStrikeoutOffset( 0 ) - , mnBStrikeoutSize( 0 ) - , mnBStrikeoutOffset( 0 ) - , mnDStrikeoutSize( 0 ) - , mnDStrikeoutOffset1( 0 ) - , mnDStrikeoutOffset2( 0 ) -{ - // intialize the used font name - if( rFontSelData.mpFontData ) - { - SetFamilyName( rFontSelData.mpFontData->GetFamilyName() ); - SetStyleName( rFontSelData.mpFontData->GetStyleName() ); - mbDevice = rFontSelData.mpFontData->mbDevice; - mbKernableFont = true; - } - else - { - sal_Int32 nTokenPos = 0; - SetFamilyName( GetNextFontToken( rFontSelData.GetFamilyName(), nTokenPos ) ); - SetStyleName( rFontSelData.GetStyleName() ); - mbDevice = false; - mbKernableFont = false; - } -} - -void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev ) -{ - long nDescent = mnDescent; - if ( nDescent <= 0 ) - { - nDescent = mnAscent / 10; - if ( !nDescent ) - nDescent = 1; - } - - // #i55341# for some fonts it is not a good idea to calculate - // their text line metrics from the real font descent - // => work around this problem just for these fonts - if( 3*nDescent > mnAscent ) - nDescent = mnAscent / 3; - - long nLineHeight = ((nDescent*25)+50) / 100; - if ( !nLineHeight ) - nLineHeight = 1; - long nLineHeight2 = nLineHeight / 2; - if ( !nLineHeight2 ) - nLineHeight2 = 1; - - long nBLineHeight = ((nDescent*50)+50) / 100; - if ( nBLineHeight == nLineHeight ) - nBLineHeight++; - long nBLineHeight2 = nBLineHeight/2; - if ( !nBLineHeight2 ) - nBLineHeight2 = 1; - - long n2LineHeight = ((nDescent*16)+50) / 100; - if ( !n2LineHeight ) - n2LineHeight = 1; - long n2LineDY = n2LineHeight; - /* #117909# - * add some pixels to minimum double line distance on higher resolution devices - */ - long nMin2LineDY = 1 + pDev->ImplGetDPIY()/150; - if ( n2LineDY < nMin2LineDY ) - n2LineDY = nMin2LineDY; - long n2LineDY2 = n2LineDY/2; - if ( !n2LineDY2 ) - n2LineDY2 = 1; - - long nUnderlineOffset = mnDescent/2 + 1; - long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3); - - mnUnderlineSize = nLineHeight; - mnUnderlineOffset = nUnderlineOffset - nLineHeight2; - - mnBUnderlineSize = nBLineHeight; - mnBUnderlineOffset = nUnderlineOffset - nBLineHeight2; - - mnDUnderlineSize = n2LineHeight; - mnDUnderlineOffset1 = nUnderlineOffset - n2LineDY2 - n2LineHeight; - mnDUnderlineOffset2 = mnDUnderlineOffset1 + n2LineDY + n2LineHeight; - - long nWCalcSize = mnDescent; - if ( nWCalcSize < 6 ) - { - if ( (nWCalcSize == 1) || (nWCalcSize == 2) ) - mnWUnderlineSize = nWCalcSize; - else - mnWUnderlineSize = 3; - } - else - mnWUnderlineSize = ((nWCalcSize*50)+50) / 100; - - // #109280# the following line assures that wavelnes are never placed below the descent, however - // for most fonts the waveline then is drawn into the text, so we better keep the old solution - // pFontEntry->maMetric.mnWUnderlineOffset = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize; - mnWUnderlineOffset = nUnderlineOffset; - - mnStrikeoutSize = nLineHeight; - mnStrikeoutOffset = nStrikeoutOffset - nLineHeight2; - - mnBStrikeoutSize = nBLineHeight; - mnBStrikeoutOffset = nStrikeoutOffset - nBLineHeight2; - - mnDStrikeoutSize = n2LineHeight; - mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight; - mnDStrikeoutOffset2 = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight; -} - -void ImplFontMetricData::ImplInitAboveTextLineSize() -{ - long nIntLeading = mnIntLeading; - // TODO: assess usage of nLeading below (changed in extleading CWS) - // if no leading is available, we assume 15% of the ascent - if ( nIntLeading <= 0 ) - { - nIntLeading = mnAscent*15/100; - if ( !nIntLeading ) - nIntLeading = 1; - } - - long nLineHeight = ((nIntLeading*25)+50) / 100; - if ( !nLineHeight ) - nLineHeight = 1; - - long nBLineHeight = ((nIntLeading*50)+50) / 100; - if ( nBLineHeight == nLineHeight ) - nBLineHeight++; - - long n2LineHeight = ((nIntLeading*16)+50) / 100; - if ( !n2LineHeight ) - n2LineHeight = 1; - - long nCeiling = -mnAscent; - - mnAboveUnderlineSize = nLineHeight; - mnAboveUnderlineOffset = nCeiling + (nIntLeading - nLineHeight + 1) / 2; - - mnAboveBUnderlineSize = nBLineHeight; - mnAboveBUnderlineOffset = nCeiling + (nIntLeading - nBLineHeight + 1) / 2; - - mnAboveDUnderlineSize = n2LineHeight; - mnAboveDUnderlineOffset1 = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2; - mnAboveDUnderlineOffset2 = nCeiling + (nIntLeading + n2LineHeight + 1) / 2; - - long nWCalcSize = nIntLeading; - if ( nWCalcSize < 6 ) - { - if ( (nWCalcSize == 1) || (nWCalcSize == 2) ) - mnAboveWUnderlineSize = nWCalcSize; - else - mnAboveWUnderlineSize = 3; - } - else - mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100; - - mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2; -} - static void ImplDrawWavePixel( long nOriginX, long nOriginY, long nCurX, long nCurY, short nOrientation, @@ -2478,284 +1012,6 @@ void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth ) ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, false ); } -void OutputDevice::ImplGetEmphasisMark( PolyPolygon& rPolyPoly, bool& rPolyLine, - Rectangle& rRect1, Rectangle& rRect2, - long& rYOff, long& rWidth, - FontEmphasisMark eEmphasis, - long nHeight, short /*nOrient*/ ) -{ - static const sal_uInt8 aAccentPolyFlags[24] = - { - 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2 - }; - - static const long aAccentPos[48] = - { - 78, 0, - 348, 79, - 599, 235, - 843, 469, - 938, 574, - 990, 669, - 990, 773, - 990, 843, - 964, 895, - 921, 947, - 886, 982, - 860, 999, - 825, 999, - 764, 999, - 721, 964, - 686, 895, - 625, 791, - 556, 660, - 469, 504, - 400, 400, - 261, 252, - 61, 61, - 0, 27, - 9, 0 - }; - - rWidth = 0; - rYOff = 0; - rPolyLine = false; - - if ( !nHeight ) - return; - - FontEmphasisMark nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE; - long nDotSize = 0; - switch ( nEmphasisStyle ) - { - case EMPHASISMARK_DOT: - // Dot has 55% of the height - nDotSize = (nHeight*550)/1000; - if ( !nDotSize ) - nDotSize = 1; - if ( nDotSize <= 2 ) - rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) ); - else - { - long nRad = nDotSize/2; - Polygon aPoly( Point( nRad, nRad ), nRad, nRad ); - rPolyPoly.Insert( aPoly ); - } - rYOff = ((nHeight*250)/1000)/2; // Center to the another EmphasisMarks - rWidth = nDotSize; - break; - - case EMPHASISMARK_CIRCLE: - // Dot has 80% of the height - nDotSize = (nHeight*800)/1000; - if ( !nDotSize ) - nDotSize = 1; - if ( nDotSize <= 2 ) - rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) ); - else - { - long nRad = nDotSize/2; - Polygon aPoly( Point( nRad, nRad ), nRad, nRad ); - rPolyPoly.Insert( aPoly ); - // BorderWidth is 15% - long nBorder = (nDotSize*150)/1000; - if ( nBorder <= 1 ) - rPolyLine = true; - else - { - Polygon aPoly2( Point( nRad, nRad ), - nRad-nBorder, nRad-nBorder ); - rPolyPoly.Insert( aPoly2 ); - } - } - rWidth = nDotSize; - break; - - case EMPHASISMARK_DISC: - // Dot has 80% of the height - nDotSize = (nHeight*800)/1000; - if ( !nDotSize ) - nDotSize = 1; - if ( nDotSize <= 2 ) - rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) ); - else - { - long nRad = nDotSize/2; - Polygon aPoly( Point( nRad, nRad ), nRad, nRad ); - rPolyPoly.Insert( aPoly ); - } - rWidth = nDotSize; - break; - - case EMPHASISMARK_ACCENT: - // Dot has 80% of the height - nDotSize = (nHeight*800)/1000; - if ( !nDotSize ) - nDotSize = 1; - if ( nDotSize <= 2 ) - { - if ( nDotSize == 1 ) - { - rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) ); - rWidth = nDotSize; - } - else - { - rRect1 = Rectangle( Point(), Size( 1, 1 ) ); - rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) ); - } - } - else - { - Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2, - (const Point*)aAccentPos, - aAccentPolyFlags ); - double dScale = ((double)nDotSize)/1000.0; - aPoly.Scale( dScale, dScale ); - Polygon aTemp; - aPoly.AdaptiveSubdivide( aTemp ); - Rectangle aBoundRect = aTemp.GetBoundRect(); - rWidth = aBoundRect.GetWidth(); - nDotSize = aBoundRect.GetHeight(); - rPolyPoly.Insert( aTemp ); - } - break; - } - - // calculate position - long nOffY = 1+(mnDPIY/300); // one visible pixel space - long nSpaceY = nHeight-nDotSize; - if ( nSpaceY >= nOffY*2 ) - rYOff += nOffY; - if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) ) - rYOff += nDotSize; -} - -void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY, - const PolyPolygon& rPolyPoly, bool bPolyLine, - const Rectangle& rRect1, const Rectangle& rRect2 ) -{ - if( IsRTLEnabled() ) - // --- RTL --- mirror at basex - nX = nBaseX - (nX - nBaseX - 1); - - nX -= mnOutOffX; - nY -= mnOutOffY; - - if ( rPolyPoly.Count() ) - { - if ( bPolyLine ) - { - Polygon aPoly = rPolyPoly.GetObject( 0 ); - aPoly.Move( nX, nY ); - DrawPolyLine( aPoly ); - } - else - { - PolyPolygon aPolyPoly = rPolyPoly; - aPolyPoly.Move( nX, nY ); - DrawPolyPolygon( aPolyPoly ); - } - } - - if ( !rRect1.IsEmpty() ) - { - Rectangle aRect( Point( nX+rRect1.Left(), - nY+rRect1.Top() ), rRect1.GetSize() ); - DrawRect( aRect ); - } - - if ( !rRect2.IsEmpty() ) - { - Rectangle aRect( Point( nX+rRect2.Left(), - nY+rRect2.Top() ), rRect2.GetSize() ); - - DrawRect( aRect ); - } -} - -void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout ) -{ - Color aOldLineColor = GetLineColor(); - Color aOldFillColor = GetFillColor(); - bool bOldMap = mbMap; - GDIMetaFile* pOldMetaFile = mpMetaFile; - mpMetaFile = NULL; - EnableMapMode( false ); - - FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont ); - PolyPolygon aPolyPoly; - Rectangle aRect1; - Rectangle aRect2; - long nEmphasisYOff; - long nEmphasisWidth; - long nEmphasisHeight; - bool bPolyLine; - - if ( nEmphasisMark & EMPHASISMARK_POS_BELOW ) - nEmphasisHeight = mnEmphasisDescent; - else - nEmphasisHeight = mnEmphasisAscent; - - ImplGetEmphasisMark( aPolyPoly, bPolyLine, - aRect1, aRect2, - nEmphasisYOff, nEmphasisWidth, - nEmphasisMark, - nEmphasisHeight, mpFontEntry->mnOrientation ); - - if ( bPolyLine ) - { - SetLineColor( GetTextColor() ); - SetFillColor(); - } - else - { - SetLineColor(); - SetFillColor( GetTextColor() ); - } - - Point aOffset = Point(0,0); - - if ( nEmphasisMark & EMPHASISMARK_POS_BELOW ) - aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff; - else - aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff; - - long nEmphasisWidth2 = nEmphasisWidth / 2; - long nEmphasisHeight2 = nEmphasisHeight / 2; - aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 ); - - Point aOutPoint; - Rectangle aRectangle; - for( int nStart = 0;;) - { - sal_GlyphId aGlyphId; - if( !rSalLayout.GetNextGlyphs( 1, &aGlyphId, aOutPoint, nStart ) ) - break; - - if( !mpGraphics->GetGlyphBoundRect( aGlyphId, aRectangle ) ) - continue; - - if( !rSalLayout.IsSpacingGlyph( aGlyphId ) ) - { - Point aAdjPoint = aOffset; - aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2; - if ( mpFontEntry->mnOrientation ) - ImplRotatePos( 0, 0, aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation ); - aOutPoint += aAdjPoint; - aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 ); - ImplDrawEmphasisMark( rSalLayout.DrawBase().X(), - aOutPoint.X(), aOutPoint.Y(), - aPolyPoly, bPolyLine, aRect1, aRect2 ); - } - } - - SetLineColor( aOldLineColor ); - SetFillColor( aOldFillColor ); - EnableMapMode( bOldMap ); - mpMetaFile = pOldMetaFile; -} - bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout ) { int nX = rSalLayout.DrawBase().X(); @@ -3248,113 +1504,6 @@ void OutputDevice::SetAntialiasing( sal_uInt16 nMode ) mpAlphaVDev->SetAntialiasing( nMode ); } -void OutputDevice::SetFont( const Font& rNewFont ) -{ - - Font aFont( rNewFont ); - aFont.SetLanguage(rNewFont.GetLanguage()); - if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | DRAWMODE_SETTINGSTEXT | - DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL | - DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) ) - { - Color aTextColor( aFont.GetColor() ); - - if ( mnDrawMode & DRAWMODE_BLACKTEXT ) - aTextColor = Color( COL_BLACK ); - else if ( mnDrawMode & DRAWMODE_WHITETEXT ) - aTextColor = Color( COL_WHITE ); - else if ( mnDrawMode & DRAWMODE_GRAYTEXT ) - { - const sal_uInt8 cLum = aTextColor.GetLuminance(); - aTextColor = Color( cLum, cLum, cLum ); - } - else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT ) - aTextColor = GetSettings().GetStyleSettings().GetFontColor(); - - if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT ) - { - aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80, - (aTextColor.GetGreen() >> 1 ) | 0x80, - (aTextColor.GetBlue() >> 1 ) | 0x80 ); - } - - aFont.SetColor( aTextColor ); - - bool bTransFill = aFont.IsTransparent(); - if ( !bTransFill ) - { - Color aTextFillColor( aFont.GetFillColor() ); - - if ( mnDrawMode & DRAWMODE_BLACKFILL ) - aTextFillColor = Color( COL_BLACK ); - else if ( mnDrawMode & DRAWMODE_WHITEFILL ) - aTextFillColor = Color( COL_WHITE ); - else if ( mnDrawMode & DRAWMODE_GRAYFILL ) - { - const sal_uInt8 cLum = aTextFillColor.GetLuminance(); - aTextFillColor = Color( cLum, cLum, cLum ); - } - else if( mnDrawMode & DRAWMODE_SETTINGSFILL ) - aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor(); - else if ( mnDrawMode & DRAWMODE_NOFILL ) - { - aTextFillColor = Color( COL_TRANSPARENT ); - bTransFill = true; - } - - if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) ) - { - aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80, - (aTextFillColor.GetGreen() >> 1) | 0x80, - (aTextFillColor.GetBlue() >> 1) | 0x80 ); - } - - aFont.SetFillColor( aTextFillColor ); - } - } - - if ( mpMetaFile ) - { - mpMetaFile->AddAction( new MetaFontAction( aFont ) ); - // the color and alignment actions don't belong here - // TODO: get rid of them without breaking anything... - mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) ); - mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) ); - } - - if ( !maFont.IsSameInstance( aFont ) ) - { - // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color, - // because SetTextColor() is used for this. - // #i28759# maTextColor might have been changed behind our back, commit then, too. - if( aFont.GetColor() != COL_TRANSPARENT - && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) ) - { - maTextColor = aFont.GetColor(); - mbInitTextColor = true; - if( mpMetaFile ) - mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) ); - } - maFont = aFont; - mbNewFont = true; - - if( mpAlphaVDev ) - { - // #i30463# - // Since SetFont might change the text color, apply that only - // selectively to alpha vdev (which normally paints opaque text - // with COL_BLACK) - if( aFont.GetColor() != COL_TRANSPARENT ) - { - mpAlphaVDev->SetTextColor( COL_BLACK ); - aFont.SetColor( COL_TRANSPARENT ); - } - - mpAlphaVDev->SetFont( aFont ); - } - } -} - void OutputDevice::SetLayoutMode( sal_uLong nTextLayoutMode ) { if( mpMetaFile ) @@ -4234,105 +2383,6 @@ SalLayout* OutputDevice::ImplLayout(const OUString& rOrigStr, return pSalLayout; } -SalLayout* OutputDevice::getFallbackFont(ImplFontEntry &rFallbackFont, - FontSelectPattern &rFontSelData, int nFallbackLevel, - ImplLayoutArgs& rLayoutArgs) const -{ - rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel ); - - rLayoutArgs.ResetPos(); - SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel ); - - if (!pFallback) - return NULL; - - if (!pFallback->LayoutText(rLayoutArgs)) - { - // there is no need for a font that couldn't resolve anything - pFallback->Release(); - return NULL; - } - - pFallback->AdjustLayout( rLayoutArgs ); - - return pFallback; -} - -SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const -{ - // prepare multi level glyph fallback - MultiSalLayout* pMultiSalLayout = NULL; - ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns; - rLayoutArgs.PrepareFallback(); - rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK; - - // get list of unicodes that need glyph fallback - int nCharPos = -1; - bool bRTL = false; - OUStringBuffer aMissingCodeBuf; - while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) ) - aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] ); - rLayoutArgs.ResetPos(); - OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear(); - - FontSelectPattern aFontSelData = mpFontEntry->maFontSelData; - - // try if fallback fonts support the missing unicodes - for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel ) - { - // find a font family suited for glyph fallback -#ifndef FONTFALLBACK_HOOKS_DISABLED - // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry - // if the system-specific glyph fallback is active - aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level -#endif - ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontCollection, - aFontSelData, nFallbackLevel, aMissingCodes ); - if( !pFallbackFont ) - break; - - aFontSelData.mpFontEntry = pFallbackFont; - aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData; - if( mpFontEntry && nFallbackLevel < MAX_FALLBACK-1) - { - // ignore fallback font if it is the same as the original font - if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData ) - { - mpFontCache->Release( pFallbackFont ); - continue; - } - } - - // create and add glyph fallback layout to multilayout - SalLayout* pFallback = getFallbackFont(*pFallbackFont, aFontSelData, - nFallbackLevel, rLayoutArgs); - if (pFallback) - { - if( !pMultiSalLayout ) - pMultiSalLayout = new MultiSalLayout( *pSalLayout ); - pMultiSalLayout->AddFallback( *pFallback, - rLayoutArgs.maRuns, aFontSelData.mpFontData ); - if (nFallbackLevel == MAX_FALLBACK-1) - pMultiSalLayout->SetInComplete(); - } - - mpFontCache->Release( pFallbackFont ); - - // break when this fallback was sufficient - if( !rLayoutArgs.PrepareFallback() ) - break; - } - - if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) ) - pSalLayout = pMultiSalLayout; - - // restore orig font settings - pSalLayout->InitFont(); - rLayoutArgs.maRuns = aLayoutRuns; - - return pSalLayout; -} - bool OutputDevice::GetTextIsRTL( const OUString& rString, sal_Int32 nIndex, sal_Int32 nLen ) const { OUString aStr( rString ); @@ -5242,191 +3292,6 @@ OUString OutputDevice::GetNonMnemonicString( const OUString& rStr, sal_Int32& rM return aStr; } -int OutputDevice::GetDevFontCount() const -{ - - if( !mpGetDevFontList ) - mpGetDevFontList = mpFontCollection->GetDevFontList(); - return mpGetDevFontList->Count(); -} - -FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const -{ - - FontInfo aFontInfo; - - ImplInitFontList(); - - int nCount = GetDevFontCount(); - if( nDevFontIndex < nCount ) - { - const PhysicalFontFace& rData = *mpGetDevFontList->Get( nDevFontIndex ); - aFontInfo.SetName( rData.GetFamilyName() ); - aFontInfo.SetStyleName( rData.GetStyleName() ); - aFontInfo.SetCharSet( rData.IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); - aFontInfo.SetFamily( rData.GetFamilyType() ); - aFontInfo.SetPitch( rData.GetPitch() ); - aFontInfo.SetWeight( rData.GetWeight() ); - aFontInfo.SetItalic( rData.GetSlant() ); - aFontInfo.SetWidthType( rData.GetWidthType() ); - if( rData.IsScalable() ) - aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG; - if( rData.mbDevice ) - aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG; - } - - return aFontInfo; -} - -bool OutputDevice::AddTempDevFont( const OUString& rFileURL, const OUString& rFontName ) -{ - - ImplInitFontList(); - - if( !mpGraphics && !ImplGetGraphics() ) - return false; - - bool bRC = mpGraphics->AddTempDevFont( mpFontCollection, rFileURL, rFontName ); - if( !bRC ) - return false; - - if( mpAlphaVDev ) - mpAlphaVDev->AddTempDevFont( rFileURL, rFontName ); - - mpFontCache->Invalidate(); - return true; -} - -int OutputDevice::GetDevFontSizeCount( const Font& rFont ) const -{ - - delete mpGetDevSizeList; - - ImplInitFontList(); - mpGetDevSizeList = mpFontCollection->GetDevSizeList( rFont.GetName() ); - return mpGetDevSizeList->Count(); -} - -Size OutputDevice::GetDevFontSize( const Font& rFont, int nSizeIndex ) const -{ - - // check range - int nCount = GetDevFontSizeCount( rFont ); - if ( nSizeIndex >= nCount ) - return Size(); - - // when mapping is enabled round to .5 points - Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) ); - if ( mbMap ) - { - aSize.Height() *= 10; - MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) ); - aSize = PixelToLogic( aSize, aMap ); - aSize.Height() += 5; - aSize.Height() /= 10; - long nRound = aSize.Height() % 5; - if ( nRound >= 3 ) - aSize.Height() += (5-nRound); - else - aSize.Height() -= nRound; - aSize.Height() *= 10; - aSize = LogicToPixel( aSize, aMap ); - aSize = PixelToLogic( aSize ); - aSize.Height() += 5; - aSize.Height() /= 10; - } - return aSize; -} - -bool OutputDevice::IsFontAvailable( const OUString& rFontName ) const -{ - - PhysicalFontFamily* pFound = mpFontCollection->FindFontFamily( rFontName ); - return (pFound != NULL); -} - -FontMetric OutputDevice::GetFontMetric() const -{ - - FontMetric aMetric; - if( mbNewFont && !ImplNewFont() ) - return aMetric; - - ImplFontEntry* pEntry = mpFontEntry; - ImplFontMetricData* pMetric = &(pEntry->maMetric); - - // prepare metric - aMetric.Font::operator=( maFont ); - - // set aMetric with info from font - aMetric.SetName( maFont.GetName() ); - aMetric.SetStyleName( pMetric->GetStyleName() ); - aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) ); - aMetric.SetCharSet( pMetric->IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); - aMetric.SetFamily( pMetric->GetFamilyType() ); - aMetric.SetPitch( pMetric->GetPitch() ); - aMetric.SetWeight( pMetric->GetWeight() ); - aMetric.SetItalic( pMetric->GetSlant() ); - aMetric.SetWidthType( pMetric->GetWidthType() ); - if ( pEntry->mnOwnOrientation ) - aMetric.SetOrientation( pEntry->mnOwnOrientation ); - else - aMetric.SetOrientation( pMetric->mnOrientation ); - if( !pEntry->maMetric.mbKernableFont ) - aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC ); - - // set remaining metric fields - aMetric.mpImplMetric->mnMiscFlags = 0; - if( pMetric->mbDevice ) - aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG; - if( pMetric->mbScalableFont ) - aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG; - aMetric.mpImplMetric->mnAscent = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent ); - aMetric.mpImplMetric->mnDescent = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent ); - aMetric.mpImplMetric->mnIntLeading = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent ); - aMetric.mpImplMetric->mnExtLeading = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading ); - aMetric.mpImplMetric->mnLineHeight = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent ); - aMetric.mpImplMetric->mnSlant = ImplDevicePixelToLogicHeight( pMetric->mnSlant ); - -#ifdef UNX - // backwards compatible line metrics after fixing #i60945# - if( (meOutDevType == OUTDEV_VIRDEV) - && static_cast<const VirtualDevice*>(this)->ForceZeroExtleadBug() ) - aMetric.mpImplMetric->mnExtLeading = 0; -#endif - - return aMetric; -} - -FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const -{ - // select font, query metrics, select original font again - Font aOldFont = GetFont(); - const_cast<OutputDevice*>(this)->SetFont( rFont ); - FontMetric aMetric( GetFontMetric() ); - const_cast<OutputDevice*>(this)->SetFont( aOldFont ); - return aMetric; -} - -/** OutputDevice::GetSysFontData - * - * @param nFallbacklevel Fallback font level (0 = best matching font) - * - * Retrieve detailed font information in platform independent structure - * - * @return SystemFontData - **/ -SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const -{ - SystemFontData aSysFontData; - aSysFontData.nSize = sizeof(aSysFontData); - - if (!mpGraphics) ImplGetGraphics(); - if (mpGraphics) aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel); - - return aSysFontData; -} - /** OutputDevice::GetSysTextLayoutData * * @param rStartPt Start point of the text @@ -5500,71 +3365,6 @@ SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, c return aSysLayoutData; } -long OutputDevice::GetMinKashida() const -{ - if( mbNewFont && !ImplNewFont() ) - return 0; - - ImplFontEntry* pEntry = mpFontEntry; - ImplFontMetricData* pMetric = &(pEntry->maMetric); - return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida ); -} - -sal_Int32 OutputDevice::ValidateKashidas ( const OUString& rTxt, - sal_Int32 nIdx, sal_Int32 nLen, - sal_Int32 nKashCount, - const sal_Int32* pKashidaPos, - sal_Int32* pKashidaPosDropped ) const -{ - // do layout - SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen ); - if( !pSalLayout ) - return 0; - sal_Int32 nDropped = 0; - for( int i = 0; i < nKashCount; ++i ) - { - if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] )) - { - pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ]; - ++nDropped; - } - } - pSalLayout->Release(); - return nDropped; -} - -bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr, - int nIndex, int nLen, int nBase, MetricVector& rVector ) -{ - - rVector.clear(); - - if(nLen == 0x0FFFF) - { - SAL_INFO("sal.rtl.xub", - "GetGlyphBoundRects Suspicious arguments nLen:" << nLen); - } - - if( nIndex >= rStr.getLength() ) - return false; - - if( nLen < 0 || nIndex + nLen >= rStr.getLength() ) - { - nLen = rStr.getLength() - nIndex; - } - - Rectangle aRect; - for( int i = 0; i < nLen; i++ ) - { - if( !GetTextBoundRect( aRect, rStr, nBase, nIndex + i, 1 ) ) - break; - aRect.Move( rOrigin.X(), rOrigin.Y() ); - rVector.push_back( aRect ); - } - - return (nLen == (int)rVector.size()); -} - bool OutputDevice::GetTextBoundRect( Rectangle& rRect, const OUString& rStr, sal_Int32 nBase, sal_Int32 nIndex, sal_Int32 nLen, @@ -6033,109 +3833,4 @@ bool OutputDevice::GetTextOutline( PolyPolygon& rPolyPoly, const OUString& rStr, return true; } -bool OutputDevice::GetFontCapabilities( FontCapabilities& rFontCapabilities ) const -{ - // we need a graphics - if( !mpGraphics && !ImplGetGraphics() ) - return false; - - if( mbNewFont ) - ImplNewFont(); - if( mbInitFont ) - ImplInitFont(); - if( !mpFontEntry ) - return false; - - return mpGraphics->GetImplFontCapabilities(rFontCapabilities); -} - -bool OutputDevice::GetFontCharMap( FontCharMap& rFontCharMap ) const -{ - rFontCharMap.Reset(); - - // we need a graphics - if( !mpGraphics && !ImplGetGraphics() ) - return false; - - if( mbNewFont ) - ImplNewFont(); - if( mbInitFont ) - ImplInitFont(); - if( !mpFontEntry ) - return false; - -#ifdef ENABLE_IFC_CACHE // a little font charmap cache helps considerably - static const int NMAXITEMS = 16; - static int nUsedItems = 0, nCurItem = 0; - - struct CharMapCacheItem { const PhysicalFontFace* mpFontData; FontCharMap maCharMap; }; - static CharMapCacheItem aCache[ NMAXITEMS ]; - - const PhysicalFontFace* pFontData = mpFontEntry->maFontSelData.mpFontData; - - int i; - for( i = nUsedItems; --i >= 0; ) - if( pFontData == aCache[i].mpFontData ) - break; - if( i >= 0 ) // found in cache - { - rFontCharMap.Reset( aCache[i].maCharMap.mpImpl ); - } - else // need to cache -#endif // ENABLE_IFC_CACHE - { - const ImplFontCharMap* pNewMap = mpGraphics->GetImplFontCharMap(); - rFontCharMap.Reset( pNewMap ); - -#ifdef ENABLE_IFC_CACHE - // manage cache round-robin and insert data - CharMapCacheItem& rItem = aCache[ nCurItem ]; - rItem.mpFontData = pFontData; - rItem.maCharMap.Reset( pNewMap ); - - if( ++nCurItem >= NMAXITEMS ) - nCurItem = 0; - - if( ++nUsedItems >= NMAXITEMS ) - nUsedItems = NMAXITEMS; -#endif // ENABLE_IFC_CACHE - } - - if( rFontCharMap.IsDefaultMap() ) - return false; - return true; -} - -sal_Int32 OutputDevice::HasGlyphs( const Font& rTempFont, const OUString& rStr, - sal_Int32 nIndex, sal_Int32 nLen ) const -{ - if( nIndex >= rStr.getLength() ) - return nIndex; - sal_Int32 nEnd; - if( nLen == -1 ) - nEnd = rStr.getLength(); - else - nEnd = std::min( rStr.getLength(), nIndex + nLen ); - - DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" ); - DBG_ASSERT( nEnd <= rStr.getLength(), "String too short" ); - - // to get the map temporarily set font - const Font aOrigFont = GetFont(); - const_cast<OutputDevice&>(*this).SetFont( rTempFont ); - FontCharMap aFontCharMap; - bool bRet = GetFontCharMap( aFontCharMap ); - const_cast<OutputDevice&>(*this).SetFont( aOrigFont ); - - // if fontmap is unknown assume it doesn't have the glyphs - if( !bRet ) - return nIndex; - - for( sal_Int32 i = nIndex; nIndex < nEnd; ++i, ++nIndex ) - if( ! aFontCharMap.HasChar( rStr[i] ) ) - return nIndex; - - return -1; -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |