LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/vcl/generic/glyphs - glyphcache.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 145 217 66.8 %
Date: 2013-07-09 Functions: 23 28 82.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <stdio.h>
      22             : #include <stdlib.h>
      23             : #include <math.h>
      24             : #include <gcach_ftyp.hxx>
      25             : 
      26             : #include <vcl/svapp.hxx>
      27             : #include <vcl/bitmap.hxx>
      28             : #include <outfont.hxx>
      29             : 
      30             : #include <config_graphite.h>
      31             : #if ENABLE_GRAPHITE
      32             : #include <graphite_features.hxx>
      33             : #endif
      34             : 
      35             : #include <rtl/ustring.hxx>      // used only for string=>hashvalue
      36             : #include <osl/file.hxx>
      37             : #include <tools/debug.hxx>
      38             : 
      39             : static GlyphCache* pInstance = NULL;
      40             : 
      41         125 : GlyphCache::GlyphCache( GlyphCachePeer& rPeer )
      42             : :   mrPeer( rPeer ),
      43             :     mnMaxSize( 1500000 ),
      44             :     mnBytesUsed(sizeof(GlyphCache)),
      45             :     mnLruIndex(0),
      46             :     mnGlyphCount(0),
      47             :     mpCurrentGCFont(NULL),
      48         125 :     mpFtManager(NULL)
      49             : {
      50         125 :     pInstance = this;
      51         125 :     mpFtManager = new FreetypeManager;
      52         125 : }
      53             : 
      54             : 
      55         250 : GlyphCache::~GlyphCache()
      56             : {
      57         125 :     InvalidateAllGlyphs();
      58         125 :     delete mpFtManager;
      59         125 : }
      60             : 
      61             : 
      62         125 : void GlyphCache::InvalidateAllGlyphs()
      63             : {
      64        2475 :     for( FontList::iterator it = maFontList.begin(), end = maFontList.end(); it != end; ++it )
      65             :     {
      66        2350 :         ServerFont* pServerFont = it->second;
      67        2350 :         mrPeer.RemovingFont(*pServerFont);
      68        2350 :         delete pServerFont;
      69             :     }
      70             : 
      71         125 :     maFontList.clear();
      72         125 :     mpCurrentGCFont = NULL;
      73         125 : }
      74             : 
      75             : 
      76             : inline
      77      185431 : size_t GlyphCache::IFSD_Hash::operator()( const FontSelectPattern& rFontSelData ) const
      78             : {
      79             :     // TODO: is it worth to improve this hash function?
      80      185431 :     sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFontSelData.mpFontData );
      81             : #if ENABLE_GRAPHITE
      82      185431 :     if (rFontSelData.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
      83             :         != -1)
      84             :     {
      85           0 :         OString aFeatName = OUStringToOString( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
      86           0 :         nFontId ^= aFeatName.hashCode();
      87             :     }
      88             : #endif
      89      185431 :     size_t nHash = nFontId << 8;
      90      185431 :     nHash   += rFontSelData.mnHeight;
      91      185431 :     nHash   += rFontSelData.mnOrientation;
      92      185431 :     nHash   += rFontSelData.mbVertical;
      93      185431 :     nHash   += rFontSelData.GetSlant();
      94      185431 :     nHash   += rFontSelData.GetWeight();
      95             : #if ENABLE_GRAPHITE
      96      185431 :     nHash   += rFontSelData.meLanguage;
      97             : #endif
      98      185431 :     return nHash;
      99             : }
     100             : 
     101             : 
     102      189655 : bool GlyphCache::IFSD_Equal::operator()( const FontSelectPattern& rA, const FontSelectPattern& rB) const
     103             : {
     104             :     // check font ids
     105      189655 :     sal_IntPtr nFontIdA = reinterpret_cast<sal_IntPtr>( rA.mpFontData );
     106      189655 :     sal_IntPtr nFontIdB = reinterpret_cast<sal_IntPtr>( rB.mpFontData );
     107      189655 :     if( nFontIdA != nFontIdB )
     108         109 :         return false;
     109             : 
     110             :     // compare with the requested metrics
     111      189546 :     if( (rA.mnHeight         != rB.mnHeight)
     112      189368 :     ||  (rA.mnOrientation    != rB.mnOrientation)
     113      189368 :     ||  (rA.mbVertical       != rB.mbVertical)
     114      189368 :     ||  (rA.mbNonAntialiased != rB.mbNonAntialiased) )
     115        4734 :         return false;
     116             : 
     117      369624 :     if( (rA.GetSlant() != rB.GetSlant())
     118      184812 :     ||  (rA.GetWeight() != rB.GetWeight()) )
     119           0 :         return false;
     120             : 
     121             :     // NOTE: ignoring meFamily deliberately
     122             : 
     123             :     // compare with the requested width, allow default width
     124      184812 :     int nAWidth = rA.mnWidth != 0 ? rA.mnWidth : rA.mnHeight;
     125      184812 :     int nBWidth = rB.mnWidth != 0 ? rB.mnWidth : rB.mnHeight;
     126      184812 :     if( nAWidth != nBWidth )
     127        4081 :         return false;
     128             : 
     129             : #if ENABLE_GRAPHITE
     130      180731 :    if (rA.meLanguage != rB.meLanguage)
     131           0 :         return false;
     132             :    // check for features
     133      361462 :    if ((rA.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
     134      180731 :         != -1 ||
     135      180731 :         rB.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
     136      180731 :         != -1) && rA.maTargetName != rB.maTargetName)
     137           0 :         return false;
     138             : #endif
     139             : 
     140      180731 :     if (rA.mbEmbolden != rB.mbEmbolden)
     141           0 :         return false;
     142             : 
     143      180731 :     if (rA.maItalicMatrix != rB.maItalicMatrix)
     144           0 :         return false;
     145             : 
     146      180731 :     return true;
     147             : }
     148             : 
     149             : 
     150    13152131 : GlyphCache& GlyphCache::GetInstance()
     151             : {
     152    13152131 :     return *pInstance;
     153             : }
     154             : 
     155             : 
     156       22009 : void GlyphCache::AddFontFile( const OString& rNormalizedName, int nFaceNum,
     157             :     sal_IntPtr nFontId, const ImplDevFontAttributes& rDFA, const ExtraKernInfo* pExtraKern )
     158             : {
     159       22009 :     if( mpFtManager )
     160       22009 :         mpFtManager->AddFontFile( rNormalizedName, nFaceNum, nFontId, rDFA, pExtraKern );
     161       22009 : }
     162             : 
     163             : 
     164         127 : void GlyphCache::AnnounceFonts( ImplDevFontList* pList ) const
     165             : {
     166         127 :     if( mpFtManager )
     167         127 :         mpFtManager->AnnounceFonts( pList );
     168         127 : }
     169             : 
     170           0 : void GlyphCache::ClearFontCache()
     171             : {
     172           0 :     InvalidateAllGlyphs();
     173           0 :     if (mpFtManager)
     174           0 :         mpFtManager->ClearFontList();
     175           0 : }
     176             : 
     177             : 
     178      183081 : ServerFont* GlyphCache::CacheFont( const FontSelectPattern& rFontSelData )
     179             : {
     180             :     // a serverfont request has pFontData
     181      183081 :     if( rFontSelData.mpFontData == NULL )
     182           0 :         return NULL;
     183             :     // a serverfont request has a fontid > 0
     184      183081 :     sal_IntPtr nFontId = rFontSelData.mpFontData->GetFontId();
     185      183081 :     if( nFontId <= 0 )
     186           0 :         return NULL;
     187             : 
     188             :     // the FontList's key mpFontData member is reinterpreted as font id
     189      183081 :     FontSelectPattern aFontSelData = rFontSelData;
     190      183081 :     aFontSelData.mpFontData = reinterpret_cast<PhysicalFontFace*>( nFontId );
     191      183081 :     FontList::iterator it = maFontList.find( aFontSelData );
     192      183081 :     if( it != maFontList.end() )
     193             :     {
     194      180731 :         ServerFont* pFound = it->second;
     195      180731 :         if( pFound )
     196      180731 :             pFound->AddRef();
     197      180731 :         return pFound;
     198             :     }
     199             : 
     200             :     // font not cached yet => create new font item
     201        2350 :     ServerFont* pNew = NULL;
     202        2350 :     if( mpFtManager )
     203        2350 :         pNew = mpFtManager->CreateFont( aFontSelData );
     204             : 
     205        2350 :     if( pNew )
     206             :     {
     207        2350 :         maFontList[ aFontSelData ] = pNew;
     208        2350 :         mnBytesUsed += pNew->GetByteCount();
     209             : 
     210             :         // enable garbage collection for new font
     211        2350 :         if( !mpCurrentGCFont )
     212             :         {
     213         124 :             mpCurrentGCFont = pNew;
     214         124 :             pNew->mpNextGCFont = pNew;
     215         124 :             pNew->mpPrevGCFont = pNew;
     216             :         }
     217             :         else
     218             :         {
     219        2226 :             pNew->mpNextGCFont = mpCurrentGCFont;
     220        2226 :             pNew->mpPrevGCFont = mpCurrentGCFont->mpPrevGCFont;
     221        2226 :             pNew->mpPrevGCFont->mpNextGCFont = pNew;
     222        2226 :             mpCurrentGCFont->mpPrevGCFont = pNew;
     223             :         }
     224             :     }
     225             : 
     226        2350 :     return pNew;
     227             : }
     228             : 
     229             : 
     230      183015 : void GlyphCache::UncacheFont( ServerFont& rServerFont )
     231             : {
     232             :     // the interface for rServerFont must be const because a
     233             :     // user who wants to release it only got const ServerFonts.
     234             :     // The caching algorithm needs a non-const object
     235      183015 :     ServerFont* pFont = const_cast<ServerFont*>( &rServerFont );
     236      366030 :     if( (pFont->Release() <= 0)
     237      183015 :     &&  (mnMaxSize <= (mnBytesUsed + mrPeer.GetByteCount())) )
     238             :     {
     239           0 :         mpCurrentGCFont = pFont;
     240           0 :         GarbageCollect();
     241             :     }
     242      183015 : }
     243             : 
     244             : 
     245           0 : void GlyphCache::GarbageCollect()
     246             : {
     247             :     // when current GC font has been destroyed get another one
     248           0 :     if( !mpCurrentGCFont )
     249             :     {
     250           0 :         FontList::iterator it = maFontList.begin();
     251           0 :         if( it != maFontList.end() )
     252           0 :             mpCurrentGCFont = it->second;
     253             :     }
     254             : 
     255             :     // unless there is no other font to collect
     256           0 :     if( !mpCurrentGCFont )
     257           0 :         return;
     258             : 
     259             :     // prepare advance to next font for garbage collection
     260           0 :     ServerFont* const pServerFont = mpCurrentGCFont;
     261           0 :     mpCurrentGCFont = pServerFont->mpNextGCFont;
     262             : 
     263           0 :     if( (pServerFont == mpCurrentGCFont)    // no other fonts
     264           0 :     ||  (pServerFont->GetRefCount() > 0) )  // font still used
     265             :     {
     266             :         // try to garbage collect at least a few bytes
     267           0 :         pServerFont->GarbageCollect( mnLruIndex - mnGlyphCount/2 );
     268             :     }
     269             :     else // current GC font is unreferenced
     270             :     {
     271             :         DBG_ASSERT( (pServerFont->GetRefCount() == 0),
     272             :             "GlyphCache::GC detected RefCount underflow" );
     273             : 
     274             :         // free all pServerFont related data
     275           0 :         pServerFont->GarbageCollect( mnLruIndex+0x10000000 );
     276           0 :         if( pServerFont == mpCurrentGCFont )
     277           0 :             mpCurrentGCFont = NULL;
     278           0 :         const FontSelectPattern& rIFSD = pServerFont->GetFontSelData();
     279           0 :         maFontList.erase( rIFSD );
     280           0 :         mrPeer.RemovingFont( *pServerFont );
     281           0 :         mnBytesUsed -= pServerFont->GetByteCount();
     282             : 
     283             :         // remove font from list of garbage collected fonts
     284           0 :         if( pServerFont->mpPrevGCFont )
     285           0 :             pServerFont->mpPrevGCFont->mpNextGCFont = pServerFont->mpNextGCFont;
     286           0 :         if( pServerFont->mpNextGCFont )
     287           0 :             pServerFont->mpNextGCFont->mpPrevGCFont = pServerFont->mpPrevGCFont;
     288           0 :         if( pServerFont == mpCurrentGCFont )
     289           0 :             mpCurrentGCFont = NULL;
     290             : 
     291           0 :         delete pServerFont;
     292             :     }
     293             : }
     294             : 
     295             : 
     296    13151913 : inline void GlyphCache::UsingGlyph( ServerFont&, GlyphData& rGlyphData )
     297             : {
     298    13151913 :     rGlyphData.SetLruValue( mnLruIndex++ );
     299    13151913 : }
     300             : 
     301             : 
     302       24425 : inline void GlyphCache::AddedGlyph( ServerFont& rServerFont, GlyphData& rGlyphData )
     303             : {
     304       24425 :     ++mnGlyphCount;
     305       24425 :     mnBytesUsed += sizeof( rGlyphData );
     306       24425 :     UsingGlyph( rServerFont, rGlyphData );
     307       24425 :     GrowNotify();
     308       24425 : }
     309             : 
     310             : 
     311       24425 : void GlyphCache::GrowNotify()
     312             : {
     313       24425 :     if( (mnBytesUsed + mrPeer.GetByteCount()) > mnMaxSize )
     314           0 :         GarbageCollect();
     315       24425 : }
     316             : 
     317             : 
     318           0 : inline void GlyphCache::RemovingGlyph( ServerFont& rSF, GlyphData& rGD, int nGlyphIndex )
     319             : {
     320           0 :     mrPeer.RemovingGlyph( rSF, rGD, nGlyphIndex );
     321           0 :     mnBytesUsed -= sizeof( GlyphData );
     322           0 :     --mnGlyphCount;
     323           0 : }
     324             : 
     325             : 
     326        2350 : void ServerFont::ReleaseFromGarbageCollect()
     327             : {
     328             :     // remove from GC list
     329        2350 :     ServerFont* pPrev = mpPrevGCFont;
     330        2350 :     ServerFont* pNext = mpNextGCFont;
     331        2350 :     if( pPrev ) pPrev->mpNextGCFont = pNext;
     332        2350 :     if( pNext ) pNext->mpPrevGCFont = pPrev;
     333        2350 :     mpPrevGCFont = NULL;
     334        2350 :     mpNextGCFont = NULL;
     335        2350 : }
     336             : 
     337             : 
     338      184761 : long ServerFont::Release() const
     339             : {
     340             :     DBG_ASSERT( mnRefCount > 0, "ServerFont: RefCount underflow" );
     341      184761 :     return --mnRefCount;
     342             : }
     343             : 
     344             : 
     345    13151913 : GlyphData& ServerFont::GetGlyphData( int nGlyphIndex )
     346             : {
     347             :     // usually the GlyphData is cached
     348    13151913 :     GlyphList::iterator it = maGlyphList.find( nGlyphIndex );
     349    13151913 :     if( it != maGlyphList.end() ) {
     350    13127488 :         GlyphData& rGlyphData = it->second;
     351    13127488 :         GlyphCache::GetInstance().UsingGlyph( *this, rGlyphData );
     352    13127488 :         return rGlyphData;
     353             :     }
     354             : 
     355             :     // sometimes not => we need to create and initialize it ourselves
     356       24425 :     GlyphData& rGlyphData = maGlyphList[ nGlyphIndex ];
     357       24425 :     mnBytesUsed += sizeof( GlyphData );
     358       24425 :     InitGlyphData( nGlyphIndex, rGlyphData );
     359       24425 :     GlyphCache::GetInstance().AddedGlyph( *this, rGlyphData );
     360       24425 :     return rGlyphData;
     361             : }
     362             : 
     363             : 
     364           0 : void ServerFont::GarbageCollect( long nMinLruIndex )
     365             : {
     366           0 :     GlyphList::iterator it_next = maGlyphList.begin();
     367           0 :     while( it_next != maGlyphList.end() )
     368             :     {
     369           0 :         GlyphList::iterator it = it_next++;
     370           0 :         GlyphData& rGD = it->second;
     371           0 :         if( (nMinLruIndex - rGD.GetLruValue()) > 0 )
     372             :         {
     373             :             OSL_ASSERT( mnBytesUsed >= sizeof(GlyphData) );
     374           0 :             mnBytesUsed -= sizeof( GlyphData );
     375           0 :             GlyphCache::GetInstance().RemovingGlyph( *this, rGD, it->first );
     376           0 :             maGlyphList.erase( it );
     377           0 :             it_next = maGlyphList.begin();
     378             :         }
     379             :     }
     380           0 : }
     381             : 
     382             : 
     383        4892 : ImplServerFontEntry::ImplServerFontEntry( FontSelectPattern& rFSD )
     384             : :   ImplFontEntry( rFSD )
     385             : ,   mpServerFont( NULL )
     386        4892 : ,   mbGotFontOptions( false )
     387        4892 : {}
     388             : 
     389             : 
     390        2350 : void ImplServerFontEntry::SetServerFont(ServerFont* p)
     391             : {
     392        2350 :     if (p == mpServerFont)
     393        2350 :         return;
     394        2350 :     if (mpServerFont)
     395           0 :         mpServerFont->Release();
     396        2350 :     mpServerFont = p;
     397        2350 :     if (mpServerFont)
     398        2350 :         mpServerFont->AddRef();
     399             : }
     400             : 
     401       11706 : ImplServerFontEntry::~ImplServerFontEntry()
     402             : {
     403             :     // TODO: remove the ServerFont here instead of in the GlyphCache
     404        3902 :     if (mpServerFont)
     405        1746 :         mpServerFont->Release();
     406        7804 : }
     407             : 
     408             : 
     409        5969 : ExtraKernInfo::ExtraKernInfo( sal_IntPtr nFontId )
     410             : :   mbInitialized( false ),
     411             :     mnFontId( nFontId ),
     412        5969 :     maUnicodeKernPairs( 0 )
     413        5969 : {}
     414             : 
     415             : 
     416           0 : int ExtraKernInfo::GetUnscaledKernPairs( ImplKernPairData** ppKernPairs ) const
     417             : {
     418           0 :     if( !mbInitialized )
     419           0 :         Initialize();
     420             : 
     421             :     // return early if no kerning available
     422           0 :     if( maUnicodeKernPairs.empty() )
     423           0 :         return 0;
     424             : 
     425             :     // allocate kern pair table
     426           0 :     int nKernCount = maUnicodeKernPairs.size();
     427           0 :     *ppKernPairs = new ImplKernPairData[ nKernCount ];
     428             : 
     429             :     // fill in unicode kern pairs with the kern value scaled to the font width
     430           0 :     ImplKernPairData* pKernData = *ppKernPairs;
     431           0 :     UnicodeKernPairs::const_iterator it = maUnicodeKernPairs.begin();
     432           0 :     for(; it != maUnicodeKernPairs.end(); ++it )
     433           0 :         *(pKernData++) = *it;
     434             : 
     435           0 :     return nKernCount;
     436         465 : }
     437             : 
     438             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10