1*9f62ea84SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*9f62ea84SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*9f62ea84SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*9f62ea84SAndrew Rist * distributed with this work for additional information 6*9f62ea84SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*9f62ea84SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*9f62ea84SAndrew Rist * "License"); you may not use this file except in compliance 9*9f62ea84SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*9f62ea84SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*9f62ea84SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*9f62ea84SAndrew Rist * software distributed under the License is distributed on an 15*9f62ea84SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*9f62ea84SAndrew Rist * KIND, either express or implied. See the License for the 17*9f62ea84SAndrew Rist * specific language governing permissions and limitations 18*9f62ea84SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*9f62ea84SAndrew Rist *************************************************************/ 21*9f62ea84SAndrew Rist 22*9f62ea84SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_vcl.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include <stdio.h> 28cdf0e10cSrcweir #include <stdlib.h> 29cdf0e10cSrcweir #include <math.h> 30cdf0e10cSrcweir 31cdf0e10cSrcweir #include <gcach_ftyp.hxx> 32cdf0e10cSrcweir 33cdf0e10cSrcweir #include <vcl/svapp.hxx> 34cdf0e10cSrcweir #include <vcl/bitmap.hxx> 35cdf0e10cSrcweir #include <vcl/salbtype.hxx> 36cdf0e10cSrcweir 37cdf0e10cSrcweir #include <outfont.hxx> 38cdf0e10cSrcweir 39cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE 40cdf0e10cSrcweir #include <graphite_features.hxx> 41cdf0e10cSrcweir #endif 42cdf0e10cSrcweir 43cdf0e10cSrcweir #include <rtl/ustring.hxx> // used only for string=>hashvalue 44cdf0e10cSrcweir #include <osl/file.hxx> 45cdf0e10cSrcweir #include <tools/debug.hxx> 46cdf0e10cSrcweir 47cdf0e10cSrcweir // ======================================================================= 48cdf0e10cSrcweir // GlyphCache 49cdf0e10cSrcweir // ======================================================================= 50cdf0e10cSrcweir 51cdf0e10cSrcweir static GlyphCache* pInstance = NULL; 52cdf0e10cSrcweir 53cdf0e10cSrcweir GlyphCache::GlyphCache( GlyphCachePeer& rPeer ) 54cdf0e10cSrcweir : mrPeer( rPeer ), 55cdf0e10cSrcweir mnMaxSize( 1500000 ), 56cdf0e10cSrcweir mnBytesUsed(sizeof(GlyphCache)), 57cdf0e10cSrcweir mnLruIndex(0), 58cdf0e10cSrcweir mnGlyphCount(0), 59cdf0e10cSrcweir mpCurrentGCFont(NULL), 60cdf0e10cSrcweir mpFtManager(NULL) 61cdf0e10cSrcweir { 62cdf0e10cSrcweir pInstance = this; 63cdf0e10cSrcweir mpFtManager = new FreetypeManager; 64cdf0e10cSrcweir } 65cdf0e10cSrcweir 66cdf0e10cSrcweir // ----------------------------------------------------------------------- 67cdf0e10cSrcweir 68cdf0e10cSrcweir GlyphCache::~GlyphCache() 69cdf0e10cSrcweir { 70cdf0e10cSrcweir InvalidateAllGlyphs(); 71cdf0e10cSrcweir if( mpFtManager ) 72cdf0e10cSrcweir delete mpFtManager; 73cdf0e10cSrcweir } 74cdf0e10cSrcweir 75cdf0e10cSrcweir // ----------------------------------------------------------------------- 76cdf0e10cSrcweir 77cdf0e10cSrcweir void GlyphCache::InvalidateAllGlyphs() 78cdf0e10cSrcweir { 79cdf0e10cSrcweir // an application about to exit can omit garbage collecting the heap 80cdf0e10cSrcweir // since it makes things slower and introduces risks if the heap was not perfect 81cdf0e10cSrcweir // for debugging, for memory grinding or leak checking the env allows to force GC 82cdf0e10cSrcweir const char* pEnv = getenv( "SAL_FORCE_GC_ON_EXIT" ); 83cdf0e10cSrcweir if( pEnv && (*pEnv != '0') ) 84cdf0e10cSrcweir { 85cdf0e10cSrcweir // uncache of all glyph shapes and metrics 86cdf0e10cSrcweir for( FontList::iterator it = maFontList.begin(); it != maFontList.end(); ++it ) 87cdf0e10cSrcweir delete const_cast<ServerFont*>( it->second ); 88cdf0e10cSrcweir maFontList.clear(); 89cdf0e10cSrcweir mpCurrentGCFont = NULL; 90cdf0e10cSrcweir } 91cdf0e10cSrcweir } 92cdf0e10cSrcweir 93cdf0e10cSrcweir // ----------------------------------------------------------------------- 94cdf0e10cSrcweir 95cdf0e10cSrcweir inline 96cdf0e10cSrcweir size_t GlyphCache::IFSD_Hash::operator()( const ImplFontSelectData& rFontSelData ) const 97cdf0e10cSrcweir { 98cdf0e10cSrcweir // TODO: is it worth to improve this hash function? 99cdf0e10cSrcweir sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFontSelData.mpFontData ); 100cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE 101cdf0e10cSrcweir if (rFontSelData.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX) 102cdf0e10cSrcweir != STRING_NOTFOUND) 103cdf0e10cSrcweir { 104cdf0e10cSrcweir rtl::OString aFeatName = rtl::OUStringToOString( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 ); 105cdf0e10cSrcweir nFontId ^= aFeatName.hashCode(); 106cdf0e10cSrcweir } 107cdf0e10cSrcweir #endif 108cdf0e10cSrcweir size_t nHash = nFontId << 8; 109cdf0e10cSrcweir nHash += rFontSelData.mnHeight; 110cdf0e10cSrcweir nHash += rFontSelData.mnOrientation; 111cdf0e10cSrcweir nHash += rFontSelData.mbVertical; 112cdf0e10cSrcweir nHash += rFontSelData.meItalic; 113cdf0e10cSrcweir nHash += rFontSelData.meWeight; 114cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE 115cdf0e10cSrcweir nHash += rFontSelData.meLanguage; 116cdf0e10cSrcweir #endif 117cdf0e10cSrcweir return nHash; 118cdf0e10cSrcweir } 119cdf0e10cSrcweir 120cdf0e10cSrcweir // ----------------------------------------------------------------------- 121cdf0e10cSrcweir 122cdf0e10cSrcweir bool GlyphCache::IFSD_Equal::operator()( const ImplFontSelectData& rA, const ImplFontSelectData& rB) const 123cdf0e10cSrcweir { 124cdf0e10cSrcweir // check font ids 125cdf0e10cSrcweir sal_IntPtr nFontIdA = reinterpret_cast<sal_IntPtr>( rA.mpFontData ); 126cdf0e10cSrcweir sal_IntPtr nFontIdB = reinterpret_cast<sal_IntPtr>( rB.mpFontData ); 127cdf0e10cSrcweir if( nFontIdA != nFontIdB ) 128cdf0e10cSrcweir return false; 129cdf0e10cSrcweir 130cdf0e10cSrcweir // compare with the requested metrics 131cdf0e10cSrcweir if( (rA.mnHeight != rB.mnHeight) 132cdf0e10cSrcweir || (rA.mnOrientation != rB.mnOrientation) 133cdf0e10cSrcweir || (rA.mbVertical != rB.mbVertical) 134cdf0e10cSrcweir || (rA.mbNonAntialiased != rB.mbNonAntialiased) ) 135cdf0e10cSrcweir return false; 136cdf0e10cSrcweir 137cdf0e10cSrcweir if( (rA.meItalic != rB.meItalic) 138cdf0e10cSrcweir || (rA.meWeight != rB.meWeight) ) 139cdf0e10cSrcweir return false; 140cdf0e10cSrcweir 141cdf0e10cSrcweir // NOTE: ignoring meFamily deliberately 142cdf0e10cSrcweir 143cdf0e10cSrcweir // compare with the requested width, allow default width 144cdf0e10cSrcweir if( (rA.mnWidth != rB.mnWidth) 145cdf0e10cSrcweir && ((rA.mnHeight != rB.mnWidth) || (rA.mnWidth != 0)) ) 146cdf0e10cSrcweir return false; 147cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE 148cdf0e10cSrcweir if (rA.meLanguage != rB.meLanguage) 149cdf0e10cSrcweir return false; 150cdf0e10cSrcweir // check for features 151cdf0e10cSrcweir if ((rA.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX) 152cdf0e10cSrcweir != STRING_NOTFOUND || 153cdf0e10cSrcweir rB.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX) 154cdf0e10cSrcweir != STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName) 155cdf0e10cSrcweir return false; 156cdf0e10cSrcweir #endif 157cdf0e10cSrcweir return true; 158cdf0e10cSrcweir } 159cdf0e10cSrcweir 160cdf0e10cSrcweir // ----------------------------------------------------------------------- 161cdf0e10cSrcweir 162cdf0e10cSrcweir GlyphCache& GlyphCache::GetInstance() 163cdf0e10cSrcweir { 164cdf0e10cSrcweir return *pInstance; 165cdf0e10cSrcweir } 166cdf0e10cSrcweir 167cdf0e10cSrcweir // ----------------------------------------------------------------------- 168cdf0e10cSrcweir 169cdf0e10cSrcweir void GlyphCache::LoadFonts() 170cdf0e10cSrcweir { 171cdf0e10cSrcweir if( const char* pFontPath = ::getenv( "SAL_FONTPATH_PRIVATE" ) ) 172cdf0e10cSrcweir AddFontPath( String::CreateFromAscii( pFontPath ) ); 173cdf0e10cSrcweir const String& rFontPath = Application::GetFontPath(); 174cdf0e10cSrcweir if( rFontPath.Len() > 0 ) 175cdf0e10cSrcweir AddFontPath( rFontPath ); 176cdf0e10cSrcweir } 177cdf0e10cSrcweir 178cdf0e10cSrcweir // ----------------------------------------------------------------------- 179cdf0e10cSrcweir 180cdf0e10cSrcweir void GlyphCache::ClearFontPath() 181cdf0e10cSrcweir { 182cdf0e10cSrcweir if( mpFtManager ) 183cdf0e10cSrcweir mpFtManager->ClearFontList(); 184cdf0e10cSrcweir } 185cdf0e10cSrcweir 186cdf0e10cSrcweir // ----------------------------------------------------------------------- 187cdf0e10cSrcweir 188cdf0e10cSrcweir void GlyphCache::AddFontPath( const String& rFontPath ) 189cdf0e10cSrcweir { 190cdf0e10cSrcweir if( !mpFtManager ) 191cdf0e10cSrcweir return; 192cdf0e10cSrcweir 193cdf0e10cSrcweir for( xub_StrLen nBreaker1 = 0, nBreaker2 = 0; nBreaker2 != STRING_LEN; nBreaker1 = nBreaker2 + 1 ) 194cdf0e10cSrcweir { 195cdf0e10cSrcweir nBreaker2 = rFontPath.Search( ';', nBreaker1 ); 196cdf0e10cSrcweir if( nBreaker2 == STRING_NOTFOUND ) 197cdf0e10cSrcweir nBreaker2 = STRING_LEN; 198cdf0e10cSrcweir 199cdf0e10cSrcweir ::rtl::OUString aUrlName; 200cdf0e10cSrcweir osl::FileBase::getFileURLFromSystemPath( rFontPath.Copy( nBreaker1, nBreaker2 ), aUrlName ); 201cdf0e10cSrcweir mpFtManager->AddFontDir( aUrlName ); 202cdf0e10cSrcweir } 203cdf0e10cSrcweir } 204cdf0e10cSrcweir 205cdf0e10cSrcweir // ----------------------------------------------------------------------- 206cdf0e10cSrcweir 207cdf0e10cSrcweir void GlyphCache::AddFontFile( const rtl::OString& rNormalizedName, int nFaceNum, 208cdf0e10cSrcweir sal_IntPtr nFontId, const ImplDevFontAttributes& rDFA, const ExtraKernInfo* pExtraKern ) 209cdf0e10cSrcweir { 210cdf0e10cSrcweir if( mpFtManager ) 211cdf0e10cSrcweir mpFtManager->AddFontFile( rNormalizedName, nFaceNum, nFontId, rDFA, pExtraKern ); 212cdf0e10cSrcweir } 213cdf0e10cSrcweir 214cdf0e10cSrcweir // ----------------------------------------------------------------------- 215cdf0e10cSrcweir 216cdf0e10cSrcweir void GlyphCache::AnnounceFonts( ImplDevFontList* pList ) const 217cdf0e10cSrcweir { 218cdf0e10cSrcweir if( mpFtManager ) 219cdf0e10cSrcweir mpFtManager->AnnounceFonts( pList ); 220cdf0e10cSrcweir // VirtDevServerFont::AnnounceFonts( pList ); 221cdf0e10cSrcweir } 222cdf0e10cSrcweir 223cdf0e10cSrcweir // ----------------------------------------------------------------------- 224cdf0e10cSrcweir 225cdf0e10cSrcweir ServerFont* GlyphCache::CacheFont( const ImplFontSelectData& rFontSelData ) 226cdf0e10cSrcweir { 227cdf0e10cSrcweir // a serverfont request has pFontData 228cdf0e10cSrcweir if( rFontSelData.mpFontData == NULL ) 229cdf0e10cSrcweir return NULL; 230cdf0e10cSrcweir // a serverfont request has a fontid > 0 231cdf0e10cSrcweir sal_IntPtr nFontId = rFontSelData.mpFontData->GetFontId(); 232cdf0e10cSrcweir if( nFontId <= 0 ) 233cdf0e10cSrcweir return NULL; 234cdf0e10cSrcweir 235cdf0e10cSrcweir // the FontList's key mpFontData member is reinterpreted as font id 236cdf0e10cSrcweir ImplFontSelectData aFontSelData = rFontSelData; 237cdf0e10cSrcweir aFontSelData.mpFontData = reinterpret_cast<ImplFontData*>( nFontId ); 238cdf0e10cSrcweir FontList::iterator it = maFontList.find( aFontSelData ); 239cdf0e10cSrcweir if( it != maFontList.end() ) 240cdf0e10cSrcweir { 241cdf0e10cSrcweir ServerFont* pFound = it->second; 242cdf0e10cSrcweir if( pFound ) 243cdf0e10cSrcweir pFound->AddRef(); 244cdf0e10cSrcweir return pFound; 245cdf0e10cSrcweir } 246cdf0e10cSrcweir 247cdf0e10cSrcweir // font not cached yet => create new font item 248cdf0e10cSrcweir ServerFont* pNew = NULL; 249cdf0e10cSrcweir if( mpFtManager ) 250cdf0e10cSrcweir pNew = mpFtManager->CreateFont( aFontSelData ); 251cdf0e10cSrcweir // TODO: pNew = VirtDevServerFont::CreateFont( aFontSelData ); 252cdf0e10cSrcweir 253cdf0e10cSrcweir if( pNew ) 254cdf0e10cSrcweir { 255cdf0e10cSrcweir maFontList[ aFontSelData ] = pNew; 256cdf0e10cSrcweir mnBytesUsed += pNew->GetByteCount(); 257cdf0e10cSrcweir 258cdf0e10cSrcweir // enable garbage collection for new font 259cdf0e10cSrcweir if( !mpCurrentGCFont ) 260cdf0e10cSrcweir { 261cdf0e10cSrcweir mpCurrentGCFont = pNew; 262cdf0e10cSrcweir pNew->mpNextGCFont = pNew; 263cdf0e10cSrcweir pNew->mpPrevGCFont = pNew; 264cdf0e10cSrcweir } 265cdf0e10cSrcweir else 266cdf0e10cSrcweir { 267cdf0e10cSrcweir pNew->mpNextGCFont = mpCurrentGCFont; 268cdf0e10cSrcweir pNew->mpPrevGCFont = mpCurrentGCFont->mpPrevGCFont; 269cdf0e10cSrcweir pNew->mpPrevGCFont->mpNextGCFont = pNew; 270cdf0e10cSrcweir mpCurrentGCFont->mpPrevGCFont = pNew; 271cdf0e10cSrcweir } 272cdf0e10cSrcweir } 273cdf0e10cSrcweir 274cdf0e10cSrcweir return pNew; 275cdf0e10cSrcweir } 276cdf0e10cSrcweir 277cdf0e10cSrcweir // ----------------------------------------------------------------------- 278cdf0e10cSrcweir 279cdf0e10cSrcweir void GlyphCache::UncacheFont( ServerFont& rServerFont ) 280cdf0e10cSrcweir { 281cdf0e10cSrcweir // the interface for rServerFont must be const because a 282cdf0e10cSrcweir // user who wants to release it only got const ServerFonts. 283cdf0e10cSrcweir // The caching algorithm needs a non-const object 284cdf0e10cSrcweir ServerFont* pFont = const_cast<ServerFont*>( &rServerFont ); 285cdf0e10cSrcweir if( (pFont->Release() <= 0) 286cdf0e10cSrcweir && (mnMaxSize <= (mnBytesUsed + mrPeer.GetByteCount())) ) 287cdf0e10cSrcweir { 288cdf0e10cSrcweir mpCurrentGCFont = pFont; 289cdf0e10cSrcweir GarbageCollect(); 290cdf0e10cSrcweir } 291cdf0e10cSrcweir } 292cdf0e10cSrcweir 293cdf0e10cSrcweir // ----------------------------------------------------------------------- 294cdf0e10cSrcweir 295cdf0e10cSrcweir sal_uLong GlyphCache::CalcByteCount() const 296cdf0e10cSrcweir { 297cdf0e10cSrcweir sal_uLong nCacheSize = sizeof(*this); 298cdf0e10cSrcweir for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it ) 299cdf0e10cSrcweir { 300cdf0e10cSrcweir const ServerFont* pSF = it->second; 301cdf0e10cSrcweir if( pSF ) 302cdf0e10cSrcweir nCacheSize += pSF->GetByteCount(); 303cdf0e10cSrcweir } 304cdf0e10cSrcweir // TODO: also account something for hashtable management 305cdf0e10cSrcweir return nCacheSize; 306cdf0e10cSrcweir } 307cdf0e10cSrcweir 308cdf0e10cSrcweir // ----------------------------------------------------------------------- 309cdf0e10cSrcweir 310cdf0e10cSrcweir void GlyphCache::GarbageCollect() 311cdf0e10cSrcweir { 312cdf0e10cSrcweir // when current GC font has been destroyed get another one 313cdf0e10cSrcweir if( !mpCurrentGCFont ) 314cdf0e10cSrcweir { 315cdf0e10cSrcweir FontList::iterator it = maFontList.begin(); 316cdf0e10cSrcweir if( it != maFontList.end() ) 317cdf0e10cSrcweir mpCurrentGCFont = it->second; 318cdf0e10cSrcweir } 319cdf0e10cSrcweir 320cdf0e10cSrcweir // unless there is no other font to collect 321cdf0e10cSrcweir if( !mpCurrentGCFont ) 322cdf0e10cSrcweir return; 323cdf0e10cSrcweir 324cdf0e10cSrcweir // prepare advance to next font for garbage collection 325cdf0e10cSrcweir ServerFont* const pServerFont = mpCurrentGCFont; 326cdf0e10cSrcweir mpCurrentGCFont = pServerFont->mpNextGCFont; 327cdf0e10cSrcweir 328cdf0e10cSrcweir if( (pServerFont == mpCurrentGCFont) // no other fonts 329cdf0e10cSrcweir || (pServerFont->GetRefCount() > 0) ) // font still used 330cdf0e10cSrcweir { 331cdf0e10cSrcweir // try to garbage collect at least a few bytes 332cdf0e10cSrcweir pServerFont->GarbageCollect( mnLruIndex - mnGlyphCount/2 ); 333cdf0e10cSrcweir } 334cdf0e10cSrcweir else // current GC font is unreferenced 335cdf0e10cSrcweir { 336cdf0e10cSrcweir DBG_ASSERT( (pServerFont->GetRefCount() == 0), 337cdf0e10cSrcweir "GlyphCache::GC detected RefCount underflow" ); 338cdf0e10cSrcweir 339cdf0e10cSrcweir // free all pServerFont related data 340cdf0e10cSrcweir pServerFont->GarbageCollect( mnLruIndex+0x10000000 ); 341cdf0e10cSrcweir if( pServerFont == mpCurrentGCFont ) 342cdf0e10cSrcweir mpCurrentGCFont = NULL; 343cdf0e10cSrcweir const ImplFontSelectData& rIFSD = pServerFont->GetFontSelData(); 344cdf0e10cSrcweir maFontList.erase( rIFSD ); 345cdf0e10cSrcweir mrPeer.RemovingFont( *pServerFont ); 346cdf0e10cSrcweir mnBytesUsed -= pServerFont->GetByteCount(); 347cdf0e10cSrcweir 348cdf0e10cSrcweir // remove font from list of garbage collected fonts 349cdf0e10cSrcweir if( pServerFont->mpPrevGCFont ) 350cdf0e10cSrcweir pServerFont->mpPrevGCFont->mpNextGCFont = pServerFont->mpNextGCFont; 351cdf0e10cSrcweir if( pServerFont->mpNextGCFont ) 352cdf0e10cSrcweir pServerFont->mpNextGCFont->mpPrevGCFont = pServerFont->mpPrevGCFont; 353cdf0e10cSrcweir if( pServerFont == mpCurrentGCFont ) 354cdf0e10cSrcweir mpCurrentGCFont = NULL; 355cdf0e10cSrcweir 356cdf0e10cSrcweir delete pServerFont; 357cdf0e10cSrcweir } 358cdf0e10cSrcweir } 359cdf0e10cSrcweir 360cdf0e10cSrcweir // ----------------------------------------------------------------------- 361cdf0e10cSrcweir 362cdf0e10cSrcweir inline void GlyphCache::UsingGlyph( ServerFont&, GlyphData& rGlyphData ) 363cdf0e10cSrcweir { 364cdf0e10cSrcweir rGlyphData.SetLruValue( mnLruIndex++ ); 365cdf0e10cSrcweir } 366cdf0e10cSrcweir 367cdf0e10cSrcweir // ----------------------------------------------------------------------- 368cdf0e10cSrcweir 369cdf0e10cSrcweir inline void GlyphCache::AddedGlyph( ServerFont& rServerFont, GlyphData& rGlyphData ) 370cdf0e10cSrcweir { 371cdf0e10cSrcweir ++mnGlyphCount; 372cdf0e10cSrcweir mnBytesUsed += sizeof( rGlyphData ); 373cdf0e10cSrcweir UsingGlyph( rServerFont, rGlyphData ); 374cdf0e10cSrcweir GrowNotify(); 375cdf0e10cSrcweir } 376cdf0e10cSrcweir 377cdf0e10cSrcweir // ----------------------------------------------------------------------- 378cdf0e10cSrcweir 379cdf0e10cSrcweir void GlyphCache::GrowNotify() 380cdf0e10cSrcweir { 381cdf0e10cSrcweir if( (mnBytesUsed + mrPeer.GetByteCount()) > mnMaxSize ) 382cdf0e10cSrcweir GarbageCollect(); 383cdf0e10cSrcweir } 384cdf0e10cSrcweir 385cdf0e10cSrcweir // ----------------------------------------------------------------------- 386cdf0e10cSrcweir 387cdf0e10cSrcweir inline void GlyphCache::RemovingGlyph( ServerFont& rSF, GlyphData& rGD, int nGlyphIndex ) 388cdf0e10cSrcweir { 389cdf0e10cSrcweir mrPeer.RemovingGlyph( rSF, rGD, nGlyphIndex ); 390cdf0e10cSrcweir mnBytesUsed -= sizeof( GlyphData ); 391cdf0e10cSrcweir --mnGlyphCount; 392cdf0e10cSrcweir } 393cdf0e10cSrcweir 394cdf0e10cSrcweir // ======================================================================= 395cdf0e10cSrcweir // ServerFont 396cdf0e10cSrcweir // ======================================================================= 397cdf0e10cSrcweir 398cdf0e10cSrcweir ServerFont::ServerFont( const ImplFontSelectData& rFSD ) 399cdf0e10cSrcweir : maGlyphList( 0), 400cdf0e10cSrcweir maFontSelData(rFSD), 401cdf0e10cSrcweir mnExtInfo(0), 402cdf0e10cSrcweir mnRefCount(1), 403cdf0e10cSrcweir mnBytesUsed( sizeof(ServerFont) ), 404cdf0e10cSrcweir mpPrevGCFont( NULL ), 405cdf0e10cSrcweir mpNextGCFont( NULL ), 406cdf0e10cSrcweir mnCos( 0x10000), 407cdf0e10cSrcweir mnSin( 0 ), 408cdf0e10cSrcweir mnZWJ( 0 ), 409cdf0e10cSrcweir mnZWNJ( 0 ), 410cdf0e10cSrcweir mbCollectedZW( false ) 411cdf0e10cSrcweir { 412cdf0e10cSrcweir // TODO: move update of mpFontEntry into FontEntry class when 413cdf0e10cSrcweir // it becomes reponsible for the ServerFont instantiation 414cdf0e10cSrcweir ((ImplServerFontEntry*)rFSD.mpFontEntry)->SetServerFont( this ); 415cdf0e10cSrcweir 416cdf0e10cSrcweir if( rFSD.mnOrientation != 0 ) 417cdf0e10cSrcweir { 418cdf0e10cSrcweir const double dRad = rFSD.mnOrientation * ( F_2PI / 3600.0 ); 419cdf0e10cSrcweir mnCos = static_cast<long>( 0x10000 * cos( dRad ) + 0.5 ); 420cdf0e10cSrcweir mnSin = static_cast<long>( 0x10000 * sin( dRad ) + 0.5 ); 421cdf0e10cSrcweir } 422cdf0e10cSrcweir } 423cdf0e10cSrcweir 424cdf0e10cSrcweir // ----------------------------------------------------------------------- 425cdf0e10cSrcweir 426cdf0e10cSrcweir ServerFont::~ServerFont() 427cdf0e10cSrcweir { 428cdf0e10cSrcweir ReleaseFromGarbageCollect(); 429cdf0e10cSrcweir } 430cdf0e10cSrcweir 431cdf0e10cSrcweir // ----------------------------------------------------------------------- 432cdf0e10cSrcweir 433cdf0e10cSrcweir void ServerFont::ReleaseFromGarbageCollect() 434cdf0e10cSrcweir { 435cdf0e10cSrcweir // remove from GC list 436cdf0e10cSrcweir ServerFont* pPrev = mpPrevGCFont; 437cdf0e10cSrcweir ServerFont* pNext = mpNextGCFont; 438cdf0e10cSrcweir if( pPrev ) pPrev->mpNextGCFont = pNext; 439cdf0e10cSrcweir if( pNext ) pNext->mpPrevGCFont = pPrev; 440cdf0e10cSrcweir mpPrevGCFont = NULL; 441cdf0e10cSrcweir mpNextGCFont = NULL; 442cdf0e10cSrcweir } 443cdf0e10cSrcweir 444cdf0e10cSrcweir // ----------------------------------------------------------------------- 445cdf0e10cSrcweir 446cdf0e10cSrcweir long ServerFont::Release() const 447cdf0e10cSrcweir { 448cdf0e10cSrcweir DBG_ASSERT( mnRefCount > 0, "ServerFont: RefCount underflow" ); 449cdf0e10cSrcweir return --mnRefCount; 450cdf0e10cSrcweir } 451cdf0e10cSrcweir 452cdf0e10cSrcweir // ----------------------------------------------------------------------- 453cdf0e10cSrcweir 454cdf0e10cSrcweir GlyphData& ServerFont::GetGlyphData( int nGlyphIndex ) 455cdf0e10cSrcweir { 456cdf0e10cSrcweir // usually the GlyphData is cached 457cdf0e10cSrcweir GlyphList::iterator it = maGlyphList.find( nGlyphIndex ); 458cdf0e10cSrcweir if( it != maGlyphList.end() ) { 459cdf0e10cSrcweir GlyphData& rGlyphData = it->second; 460cdf0e10cSrcweir GlyphCache::GetInstance().UsingGlyph( *this, rGlyphData ); 461cdf0e10cSrcweir return rGlyphData; 462cdf0e10cSrcweir } 463cdf0e10cSrcweir 464cdf0e10cSrcweir // sometimes not => we need to create and initialize it ourselves 465cdf0e10cSrcweir GlyphData& rGlyphData = maGlyphList[ nGlyphIndex ]; 466cdf0e10cSrcweir mnBytesUsed += sizeof( GlyphData ); 467cdf0e10cSrcweir InitGlyphData( nGlyphIndex, rGlyphData ); 468cdf0e10cSrcweir GlyphCache::GetInstance().AddedGlyph( *this, rGlyphData ); 469cdf0e10cSrcweir return rGlyphData; 470cdf0e10cSrcweir } 471cdf0e10cSrcweir 472cdf0e10cSrcweir // ----------------------------------------------------------------------- 473cdf0e10cSrcweir 474cdf0e10cSrcweir void ServerFont::GarbageCollect( long nMinLruIndex ) 475cdf0e10cSrcweir { 476cdf0e10cSrcweir GlyphList::iterator it_next = maGlyphList.begin(); 477cdf0e10cSrcweir while( it_next != maGlyphList.end() ) 478cdf0e10cSrcweir { 479cdf0e10cSrcweir GlyphList::iterator it = it_next++; 480cdf0e10cSrcweir GlyphData& rGD = it->second; 481cdf0e10cSrcweir if( (nMinLruIndex - rGD.GetLruValue()) > 0 ) 482cdf0e10cSrcweir { 483cdf0e10cSrcweir OSL_ASSERT( mnBytesUsed >= sizeof(GlyphData) ); 484cdf0e10cSrcweir mnBytesUsed -= sizeof( GlyphData ); 485cdf0e10cSrcweir GlyphCache::GetInstance().RemovingGlyph( *this, rGD, it->first ); 486cdf0e10cSrcweir maGlyphList.erase( it ); 487cdf0e10cSrcweir it_next = maGlyphList.begin(); 488cdf0e10cSrcweir } 489cdf0e10cSrcweir } 490cdf0e10cSrcweir } 491cdf0e10cSrcweir 492cdf0e10cSrcweir // ----------------------------------------------------------------------- 493cdf0e10cSrcweir 494cdf0e10cSrcweir Point ServerFont::TransformPoint( const Point& rPoint ) const 495cdf0e10cSrcweir { 496cdf0e10cSrcweir if( mnCos == 0x10000 ) 497cdf0e10cSrcweir return rPoint; 498cdf0e10cSrcweir // TODO: use 32x32=>64bit intermediate 499cdf0e10cSrcweir const double dCos = mnCos * (1.0 / 0x10000); 500cdf0e10cSrcweir const double dSin = mnSin * (1.0 / 0x10000); 501cdf0e10cSrcweir long nX = (long)(rPoint.X() * dCos + rPoint.Y() * dSin); 502cdf0e10cSrcweir long nY = (long)(rPoint.Y() * dCos - rPoint.X() * dSin); 503cdf0e10cSrcweir return Point( nX, nY ); 504cdf0e10cSrcweir } 505cdf0e10cSrcweir 506cdf0e10cSrcweir bool ServerFont::IsGlyphInvisible( int nGlyphIndex ) 507cdf0e10cSrcweir { 508cdf0e10cSrcweir if (!mbCollectedZW) 509cdf0e10cSrcweir { 510cdf0e10cSrcweir mnZWJ = GetGlyphIndex( 0x200D ); 511cdf0e10cSrcweir mnZWNJ = GetGlyphIndex( 0x200C ); 512cdf0e10cSrcweir mbCollectedZW = true; 513cdf0e10cSrcweir } 514cdf0e10cSrcweir 515cdf0e10cSrcweir if( !nGlyphIndex ) // don't hide the NotDef glyph 516cdf0e10cSrcweir return false; 517cdf0e10cSrcweir if( (nGlyphIndex == mnZWNJ) || (nGlyphIndex == mnZWJ) ) 518cdf0e10cSrcweir return true; 519cdf0e10cSrcweir 520cdf0e10cSrcweir return false; 521cdf0e10cSrcweir } 522cdf0e10cSrcweir 523cdf0e10cSrcweir // ======================================================================= 524cdf0e10cSrcweir 525cdf0e10cSrcweir ImplServerFontEntry::ImplServerFontEntry( ImplFontSelectData& rFSD ) 526cdf0e10cSrcweir : ImplFontEntry( rFSD ) 527cdf0e10cSrcweir , mpServerFont( NULL ) 528cdf0e10cSrcweir , mbGotFontOptions( false ) 529cdf0e10cSrcweir , mbValidFontOptions( false ) 530cdf0e10cSrcweir {} 531cdf0e10cSrcweir 532cdf0e10cSrcweir // ----------------------------------------------------------------------- 533cdf0e10cSrcweir 534cdf0e10cSrcweir ImplServerFontEntry::~ImplServerFontEntry() 535cdf0e10cSrcweir { 536cdf0e10cSrcweir // TODO: remove the ServerFont here instead of in the GlyphCache 537cdf0e10cSrcweir } 538cdf0e10cSrcweir 539cdf0e10cSrcweir // ======================================================================= 540cdf0e10cSrcweir 541cdf0e10cSrcweir ExtraKernInfo::ExtraKernInfo( sal_IntPtr nFontId ) 542cdf0e10cSrcweir : mbInitialized( false ), 543cdf0e10cSrcweir mnFontId( nFontId ), 544cdf0e10cSrcweir maUnicodeKernPairs( 0 ) 545cdf0e10cSrcweir {} 546cdf0e10cSrcweir 547cdf0e10cSrcweir //-------------------------------------------------------------------------- 548cdf0e10cSrcweir 549cdf0e10cSrcweir bool ExtraKernInfo::HasKernPairs() const 550cdf0e10cSrcweir { 551cdf0e10cSrcweir if( !mbInitialized ) 552cdf0e10cSrcweir Initialize(); 553cdf0e10cSrcweir return !maUnicodeKernPairs.empty(); 554cdf0e10cSrcweir } 555cdf0e10cSrcweir 556cdf0e10cSrcweir //-------------------------------------------------------------------------- 557cdf0e10cSrcweir 558cdf0e10cSrcweir int ExtraKernInfo::GetUnscaledKernPairs( ImplKernPairData** ppKernPairs ) const 559cdf0e10cSrcweir { 560cdf0e10cSrcweir if( !mbInitialized ) 561cdf0e10cSrcweir Initialize(); 562cdf0e10cSrcweir 563cdf0e10cSrcweir // return early if no kerning available 564cdf0e10cSrcweir if( maUnicodeKernPairs.empty() ) 565cdf0e10cSrcweir return 0; 566cdf0e10cSrcweir 567cdf0e10cSrcweir // allocate kern pair table 568cdf0e10cSrcweir int nKernCount = maUnicodeKernPairs.size(); 569cdf0e10cSrcweir *ppKernPairs = new ImplKernPairData[ nKernCount ]; 570cdf0e10cSrcweir 571cdf0e10cSrcweir // fill in unicode kern pairs with the kern value scaled to the font width 572cdf0e10cSrcweir ImplKernPairData* pKernData = *ppKernPairs; 573cdf0e10cSrcweir UnicodeKernPairs::const_iterator it = maUnicodeKernPairs.begin(); 574cdf0e10cSrcweir for(; it != maUnicodeKernPairs.end(); ++it ) 575cdf0e10cSrcweir *(pKernData++) = *it; 576cdf0e10cSrcweir 577cdf0e10cSrcweir return nKernCount; 578cdf0e10cSrcweir } 579cdf0e10cSrcweir 580cdf0e10cSrcweir //-------------------------------------------------------------------------- 581cdf0e10cSrcweir 582cdf0e10cSrcweir int ExtraKernInfo::GetUnscaledKernValue( sal_Unicode cLeft, sal_Unicode cRight ) const 583cdf0e10cSrcweir { 584cdf0e10cSrcweir if( !mbInitialized ) 585cdf0e10cSrcweir Initialize(); 586cdf0e10cSrcweir 587cdf0e10cSrcweir if( maUnicodeKernPairs.empty() ) 588cdf0e10cSrcweir return 0; 589cdf0e10cSrcweir 590cdf0e10cSrcweir ImplKernPairData aKernPair = { cLeft, cRight, 0 }; 591cdf0e10cSrcweir UnicodeKernPairs::const_iterator it = maUnicodeKernPairs.find( aKernPair ); 592cdf0e10cSrcweir if( it == maUnicodeKernPairs.end() ) 593cdf0e10cSrcweir return 0; 594cdf0e10cSrcweir 595cdf0e10cSrcweir int nUnscaledValue = (*it).mnKern; 596cdf0e10cSrcweir return nUnscaledValue; 597cdf0e10cSrcweir } 598cdf0e10cSrcweir 599cdf0e10cSrcweir // ======================================================================= 600cdf0e10cSrcweir 601