fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / vcl / generic / glyphs / glyphcache.cxx
bloba32b88fd82a06069f2ec75c4fca20f80f7b53b31
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <gcach_ftyp.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/bitmap.hxx>
28 #include <outfont.hxx>
30 #include <config_graphite.h>
31 #if ENABLE_GRAPHITE
32 #include <graphite_features.hxx>
33 #endif
35 #include <rtl/ustring.hxx> // used only for string=>hashvalue
36 #include <osl/file.hxx>
37 #include <tools/debug.hxx>
39 static GlyphCache* pInstance = NULL;
41 GlyphCache::GlyphCache( GlyphCachePeer& rPeer )
42 : mrPeer( rPeer ),
43 mnMaxSize( 1500000 ),
44 mnBytesUsed(sizeof(GlyphCache)),
45 mnLruIndex(0),
46 mnGlyphCount(0),
47 mpCurrentGCFont(NULL),
48 mpFtManager(NULL)
50 pInstance = this;
51 mpFtManager = new FreetypeManager;
55 GlyphCache::~GlyphCache()
57 InvalidateAllGlyphs();
58 delete mpFtManager;
62 void GlyphCache::InvalidateAllGlyphs()
64 for( FontList::iterator it = maFontList.begin(), end = maFontList.end(); it != end; ++it )
66 ServerFont* pServerFont = it->second;
67 mrPeer.RemovingFont(*pServerFont);
68 delete pServerFont;
71 maFontList.clear();
72 mpCurrentGCFont = NULL;
76 inline
77 size_t GlyphCache::IFSD_Hash::operator()( const FontSelectPattern& rFontSelData ) const
79 // TODO: is it worth to improve this hash function?
80 sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFontSelData.mpFontData );
81 #if ENABLE_GRAPHITE
82 if (rFontSelData.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
83 != -1)
85 OString aFeatName = OUStringToOString( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
86 nFontId ^= aFeatName.hashCode();
88 #endif
89 size_t nHash = nFontId << 8;
90 nHash += rFontSelData.mnHeight;
91 nHash += rFontSelData.mnOrientation;
92 nHash += rFontSelData.mbVertical;
93 nHash += rFontSelData.GetSlant();
94 nHash += rFontSelData.GetWeight();
95 #if ENABLE_GRAPHITE
96 nHash += rFontSelData.meLanguage;
97 #endif
98 return nHash;
102 bool GlyphCache::IFSD_Equal::operator()( const FontSelectPattern& rA, const FontSelectPattern& rB) const
104 // check font ids
105 sal_IntPtr nFontIdA = reinterpret_cast<sal_IntPtr>( rA.mpFontData );
106 sal_IntPtr nFontIdB = reinterpret_cast<sal_IntPtr>( rB.mpFontData );
107 if( nFontIdA != nFontIdB )
108 return false;
110 // compare with the requested metrics
111 if( (rA.mnHeight != rB.mnHeight)
112 || (rA.mnOrientation != rB.mnOrientation)
113 || (rA.mbVertical != rB.mbVertical)
114 || (rA.mbNonAntialiased != rB.mbNonAntialiased) )
115 return false;
117 if( (rA.GetSlant() != rB.GetSlant())
118 || (rA.GetWeight() != rB.GetWeight()) )
119 return false;
121 // NOTE: ignoring meFamily deliberately
123 // compare with the requested width, allow default width
124 int nAWidth = rA.mnWidth != 0 ? rA.mnWidth : rA.mnHeight;
125 int nBWidth = rB.mnWidth != 0 ? rB.mnWidth : rB.mnHeight;
126 if( nAWidth != nBWidth )
127 return false;
129 #if ENABLE_GRAPHITE
130 if (rA.meLanguage != rB.meLanguage)
131 return false;
132 // check for features
133 if ((rA.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
134 != -1 ||
135 rB.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
136 != -1) && rA.maTargetName != rB.maTargetName)
137 return false;
138 #endif
140 if (rA.mbEmbolden != rB.mbEmbolden)
141 return false;
143 if (rA.maItalicMatrix != rB.maItalicMatrix)
144 return false;
146 return true;
150 GlyphCache& GlyphCache::GetInstance()
152 return *pInstance;
156 void GlyphCache::AddFontFile( const OString& rNormalizedName, int nFaceNum,
157 sal_IntPtr nFontId, const ImplDevFontAttributes& rDFA, const ExtraKernInfo* pExtraKern )
159 if( mpFtManager )
160 mpFtManager->AddFontFile( rNormalizedName, nFaceNum, nFontId, rDFA, pExtraKern );
164 void GlyphCache::AnnounceFonts( ImplDevFontList* pList ) const
166 if( mpFtManager )
167 mpFtManager->AnnounceFonts( pList );
170 void GlyphCache::ClearFontCache()
172 InvalidateAllGlyphs();
173 if (mpFtManager)
174 mpFtManager->ClearFontList();
178 ServerFont* GlyphCache::CacheFont( const FontSelectPattern& rFontSelData )
180 // a serverfont request has pFontData
181 if( rFontSelData.mpFontData == NULL )
182 return NULL;
183 // a serverfont request has a fontid > 0
184 sal_IntPtr nFontId = rFontSelData.mpFontData->GetFontId();
185 if( nFontId <= 0 )
186 return NULL;
188 // the FontList's key mpFontData member is reinterpreted as font id
189 FontSelectPattern aFontSelData = rFontSelData;
190 aFontSelData.mpFontData = reinterpret_cast<PhysicalFontFace*>( nFontId );
191 FontList::iterator it = maFontList.find( aFontSelData );
192 if( it != maFontList.end() )
194 ServerFont* pFound = it->second;
195 if( pFound )
196 pFound->AddRef();
197 return pFound;
200 // font not cached yet => create new font item
201 ServerFont* pNew = NULL;
202 if( mpFtManager )
203 pNew = mpFtManager->CreateFont( aFontSelData );
205 if( pNew )
207 maFontList[ aFontSelData ] = pNew;
208 mnBytesUsed += pNew->GetByteCount();
210 // enable garbage collection for new font
211 if( !mpCurrentGCFont )
213 mpCurrentGCFont = pNew;
214 pNew->mpNextGCFont = pNew;
215 pNew->mpPrevGCFont = pNew;
217 else
219 pNew->mpNextGCFont = mpCurrentGCFont;
220 pNew->mpPrevGCFont = mpCurrentGCFont->mpPrevGCFont;
221 pNew->mpPrevGCFont->mpNextGCFont = pNew;
222 mpCurrentGCFont->mpPrevGCFont = pNew;
226 return pNew;
230 void GlyphCache::UncacheFont( ServerFont& rServerFont )
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 ServerFont* pFont = const_cast<ServerFont*>( &rServerFont );
236 if( (pFont->Release() <= 0)
237 && (mnMaxSize <= (mnBytesUsed + mrPeer.GetByteCount())) )
239 mpCurrentGCFont = pFont;
240 GarbageCollect();
245 void GlyphCache::GarbageCollect()
247 // when current GC font has been destroyed get another one
248 if( !mpCurrentGCFont )
250 FontList::iterator it = maFontList.begin();
251 if( it != maFontList.end() )
252 mpCurrentGCFont = it->second;
255 // unless there is no other font to collect
256 if( !mpCurrentGCFont )
257 return;
259 // prepare advance to next font for garbage collection
260 ServerFont* const pServerFont = mpCurrentGCFont;
261 mpCurrentGCFont = pServerFont->mpNextGCFont;
263 if( (pServerFont == mpCurrentGCFont) // no other fonts
264 || (pServerFont->GetRefCount() > 0) ) // font still used
266 // try to garbage collect at least a few bytes
267 pServerFont->GarbageCollect( mnLruIndex - mnGlyphCount/2 );
269 else // current GC font is unreferenced
271 DBG_ASSERT( (pServerFont->GetRefCount() == 0),
272 "GlyphCache::GC detected RefCount underflow" );
274 // free all pServerFont related data
275 pServerFont->GarbageCollect( mnLruIndex+0x10000000 );
276 if( pServerFont == mpCurrentGCFont )
277 mpCurrentGCFont = NULL;
278 const FontSelectPattern& rIFSD = pServerFont->GetFontSelData();
279 maFontList.erase( rIFSD );
280 mrPeer.RemovingFont( *pServerFont );
281 mnBytesUsed -= pServerFont->GetByteCount();
283 // remove font from list of garbage collected fonts
284 if( pServerFont->mpPrevGCFont )
285 pServerFont->mpPrevGCFont->mpNextGCFont = pServerFont->mpNextGCFont;
286 if( pServerFont->mpNextGCFont )
287 pServerFont->mpNextGCFont->mpPrevGCFont = pServerFont->mpPrevGCFont;
288 if( pServerFont == mpCurrentGCFont )
289 mpCurrentGCFont = NULL;
291 delete pServerFont;
296 inline void GlyphCache::UsingGlyph( ServerFont&, GlyphData& rGlyphData )
298 rGlyphData.SetLruValue( mnLruIndex++ );
302 inline void GlyphCache::AddedGlyph( ServerFont& rServerFont, GlyphData& rGlyphData )
304 ++mnGlyphCount;
305 mnBytesUsed += sizeof( rGlyphData );
306 UsingGlyph( rServerFont, rGlyphData );
307 GrowNotify();
311 void GlyphCache::GrowNotify()
313 if( (mnBytesUsed + mrPeer.GetByteCount()) > mnMaxSize )
314 GarbageCollect();
318 inline void GlyphCache::RemovingGlyph( ServerFont& rSF, GlyphData& rGD, int nGlyphIndex )
320 mrPeer.RemovingGlyph( rSF, rGD, nGlyphIndex );
321 mnBytesUsed -= sizeof( GlyphData );
322 --mnGlyphCount;
326 void ServerFont::ReleaseFromGarbageCollect()
328 // remove from GC list
329 ServerFont* pPrev = mpPrevGCFont;
330 ServerFont* pNext = mpNextGCFont;
331 if( pPrev ) pPrev->mpNextGCFont = pNext;
332 if( pNext ) pNext->mpPrevGCFont = pPrev;
333 mpPrevGCFont = NULL;
334 mpNextGCFont = NULL;
338 long ServerFont::Release() const
340 DBG_ASSERT( mnRefCount > 0, "ServerFont: RefCount underflow" );
341 return --mnRefCount;
345 GlyphData& ServerFont::GetGlyphData( int nGlyphIndex )
347 // usually the GlyphData is cached
348 GlyphList::iterator it = maGlyphList.find( nGlyphIndex );
349 if( it != maGlyphList.end() ) {
350 GlyphData& rGlyphData = it->second;
351 GlyphCache::GetInstance().UsingGlyph( *this, rGlyphData );
352 return rGlyphData;
355 // sometimes not => we need to create and initialize it ourselves
356 GlyphData& rGlyphData = maGlyphList[ nGlyphIndex ];
357 mnBytesUsed += sizeof( GlyphData );
358 InitGlyphData( nGlyphIndex, rGlyphData );
359 GlyphCache::GetInstance().AddedGlyph( *this, rGlyphData );
360 return rGlyphData;
364 void ServerFont::GarbageCollect( long nMinLruIndex )
366 GlyphList::iterator it_next = maGlyphList.begin();
367 while( it_next != maGlyphList.end() )
369 GlyphList::iterator it = it_next++;
370 GlyphData& rGD = it->second;
371 if( (nMinLruIndex - rGD.GetLruValue()) > 0 )
373 OSL_ASSERT( mnBytesUsed >= sizeof(GlyphData) );
374 mnBytesUsed -= sizeof( GlyphData );
375 GlyphCache::GetInstance().RemovingGlyph( *this, rGD, it->first );
376 maGlyphList.erase( it );
377 it_next = maGlyphList.begin();
383 ImplServerFontEntry::ImplServerFontEntry( FontSelectPattern& rFSD )
384 : ImplFontEntry( rFSD )
385 , mpServerFont( NULL )
386 , mbGotFontOptions( false )
390 void ImplServerFontEntry::SetServerFont(ServerFont* p)
392 if (p == mpServerFont)
393 return;
394 if (mpServerFont)
395 mpServerFont->Release();
396 mpServerFont = p;
397 if (mpServerFont)
398 mpServerFont->AddRef();
401 ImplServerFontEntry::~ImplServerFontEntry()
403 // TODO: remove the ServerFont here instead of in the GlyphCache
404 if (mpServerFont)
405 mpServerFont->Release();
409 ExtraKernInfo::ExtraKernInfo( sal_IntPtr nFontId )
410 : mbInitialized( false ),
411 mnFontId( nFontId ),
412 maUnicodeKernPairs( 0 )
416 int ExtraKernInfo::GetUnscaledKernPairs( ImplKernPairData** ppKernPairs ) const
418 if( !mbInitialized )
419 Initialize();
421 // return early if no kerning available
422 if( maUnicodeKernPairs.empty() )
423 return 0;
425 // allocate kern pair table
426 int nKernCount = maUnicodeKernPairs.size();
427 *ppKernPairs = new ImplKernPairData[ nKernCount ];
429 // fill in unicode kern pairs with the kern value scaled to the font width
430 ImplKernPairData* pKernData = *ppKernPairs;
431 UnicodeKernPairs::const_iterator it = maUnicodeKernPairs.begin();
432 for(; it != maUnicodeKernPairs.end(); ++it )
433 *(pKernData++) = *it;
435 return nKernCount;
438 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */