xref: /aoo41x/main/vcl/source/glyphs/glyphcache.cxx (revision 248a599f)
19f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
39f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
49f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
59f62ea84SAndrew Rist  * distributed with this work for additional information
69f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
79f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
89f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
99f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
109f62ea84SAndrew Rist  *
119f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
129f62ea84SAndrew Rist  *
139f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
149f62ea84SAndrew Rist  * software distributed under the License is distributed on an
159f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
179f62ea84SAndrew Rist  * specific language governing permissions and limitations
189f62ea84SAndrew Rist  * under the License.
199f62ea84SAndrew Rist  *
209f62ea84SAndrew Rist  *************************************************************/
219f62ea84SAndrew Rist 
229f62ea84SAndrew 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 
GlyphCache(GlyphCachePeer & rPeer)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 
~GlyphCache()68cdf0e10cSrcweir GlyphCache::~GlyphCache()
69cdf0e10cSrcweir {
70cdf0e10cSrcweir     InvalidateAllGlyphs();
71cdf0e10cSrcweir     if( mpFtManager )
72cdf0e10cSrcweir         delete mpFtManager;
73cdf0e10cSrcweir }
74cdf0e10cSrcweir 
75cdf0e10cSrcweir // -----------------------------------------------------------------------
76cdf0e10cSrcweir 
InvalidateAllGlyphs()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
operator ()(const ImplFontSelectData & rFontSelData) const96cdf0e10cSrcweir 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 
operator ()(const ImplFontSelectData & rA,const ImplFontSelectData & rB) const122cdf0e10cSrcweir 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 
GetInstance()162cdf0e10cSrcweir GlyphCache& GlyphCache::GetInstance()
163cdf0e10cSrcweir {
164cdf0e10cSrcweir 	return *pInstance;
165cdf0e10cSrcweir }
166cdf0e10cSrcweir 
167cdf0e10cSrcweir // -----------------------------------------------------------------------
168cdf0e10cSrcweir 
LoadFonts()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 
ClearFontPath()180cdf0e10cSrcweir void GlyphCache::ClearFontPath()
181cdf0e10cSrcweir {
182cdf0e10cSrcweir     if( mpFtManager )
183cdf0e10cSrcweir         mpFtManager->ClearFontList();
184cdf0e10cSrcweir }
185cdf0e10cSrcweir 
186cdf0e10cSrcweir // -----------------------------------------------------------------------
187cdf0e10cSrcweir 
AddFontPath(const String & rFontPath)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 
AddFontFile(const rtl::OString & rNormalizedName,int nFaceNum,sal_IntPtr nFontId,const ImplDevFontAttributes & rDFA,const ExtraKernInfo * pExtraKern)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 
AnnounceFonts(ImplDevFontList * pList) const216cdf0e10cSrcweir void GlyphCache::AnnounceFonts( ImplDevFontList* pList ) const
217cdf0e10cSrcweir {
218cdf0e10cSrcweir     if( mpFtManager )
219cdf0e10cSrcweir         mpFtManager->AnnounceFonts( pList );
220cdf0e10cSrcweir     // VirtDevServerFont::AnnounceFonts( pList );
221cdf0e10cSrcweir }
222cdf0e10cSrcweir 
223cdf0e10cSrcweir // -----------------------------------------------------------------------
224cdf0e10cSrcweir 
CacheFont(const ImplFontSelectData & rFontSelData)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 
UncacheFont(ServerFont & rServerFont)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 
CalcByteCount() const295cdf0e10cSrcweir 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 
GarbageCollect()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 
UsingGlyph(ServerFont &,GlyphData & rGlyphData)362cdf0e10cSrcweir inline void GlyphCache::UsingGlyph( ServerFont&, GlyphData& rGlyphData )
363cdf0e10cSrcweir {
364cdf0e10cSrcweir     rGlyphData.SetLruValue( mnLruIndex++ );
365cdf0e10cSrcweir }
366cdf0e10cSrcweir 
367cdf0e10cSrcweir // -----------------------------------------------------------------------
368cdf0e10cSrcweir 
AddedGlyph(ServerFont & rServerFont,GlyphData & rGlyphData)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 
GrowNotify()379cdf0e10cSrcweir void GlyphCache::GrowNotify()
380cdf0e10cSrcweir {
381cdf0e10cSrcweir     if( (mnBytesUsed + mrPeer.GetByteCount()) > mnMaxSize )
382cdf0e10cSrcweir         GarbageCollect();
383cdf0e10cSrcweir }
384cdf0e10cSrcweir 
385cdf0e10cSrcweir // -----------------------------------------------------------------------
386cdf0e10cSrcweir 
RemovingGlyph(ServerFont & rSF,GlyphData & rGD,sal_GlyphId aGlyphId)387*248a599fSHerbert Dürr inline void GlyphCache::RemovingGlyph( ServerFont& rSF, GlyphData& rGD, sal_GlyphId aGlyphId )
388cdf0e10cSrcweir {
389*248a599fSHerbert Dürr     mrPeer.RemovingGlyph( rSF, rGD, aGlyphId );
390cdf0e10cSrcweir     mnBytesUsed -= sizeof( GlyphData );
391cdf0e10cSrcweir     --mnGlyphCount;
392cdf0e10cSrcweir }
393cdf0e10cSrcweir 
394cdf0e10cSrcweir // =======================================================================
395cdf0e10cSrcweir // ServerFont
396cdf0e10cSrcweir // =======================================================================
397cdf0e10cSrcweir 
ServerFont(const ImplFontSelectData & rFSD)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 
~ServerFont()426cdf0e10cSrcweir ServerFont::~ServerFont()
427cdf0e10cSrcweir {
428cdf0e10cSrcweir     ReleaseFromGarbageCollect();
429cdf0e10cSrcweir }
430cdf0e10cSrcweir 
431cdf0e10cSrcweir // -----------------------------------------------------------------------
432cdf0e10cSrcweir 
ReleaseFromGarbageCollect()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 
Release() const446cdf0e10cSrcweir long ServerFont::Release() const
447cdf0e10cSrcweir {
448cdf0e10cSrcweir     DBG_ASSERT( mnRefCount > 0, "ServerFont: RefCount underflow" );
449cdf0e10cSrcweir     return --mnRefCount;
450cdf0e10cSrcweir }
451cdf0e10cSrcweir 
452cdf0e10cSrcweir // -----------------------------------------------------------------------
453cdf0e10cSrcweir 
GetGlyphData(sal_GlyphId aGlyphId)454*248a599fSHerbert Dürr GlyphData& ServerFont::GetGlyphData( sal_GlyphId aGlyphId )
455cdf0e10cSrcweir {
456cdf0e10cSrcweir     // usually the GlyphData is cached
457*248a599fSHerbert Dürr     GlyphList::iterator it = maGlyphList.find( aGlyphId );
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
465*248a599fSHerbert Dürr     GlyphData& rGlyphData = maGlyphList[ aGlyphId ];
466cdf0e10cSrcweir     mnBytesUsed += sizeof( GlyphData );
467*248a599fSHerbert Dürr     InitGlyphData( aGlyphId, rGlyphData );
468cdf0e10cSrcweir     GlyphCache::GetInstance().AddedGlyph( *this, rGlyphData );
469cdf0e10cSrcweir     return rGlyphData;
470cdf0e10cSrcweir }
471cdf0e10cSrcweir 
472cdf0e10cSrcweir // -----------------------------------------------------------------------
473cdf0e10cSrcweir 
GarbageCollect(long nMinLruIndex)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 
TransformPoint(const Point & rPoint) const494cdf0e10cSrcweir 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 
IsGlyphInvisible(sal_GlyphId aGlyphId)506*248a599fSHerbert Dürr bool ServerFont::IsGlyphInvisible( sal_GlyphId aGlyphId )
507cdf0e10cSrcweir {
508cdf0e10cSrcweir     if (!mbCollectedZW)
509cdf0e10cSrcweir     {
510cdf0e10cSrcweir         mnZWJ = GetGlyphIndex( 0x200D );
511cdf0e10cSrcweir         mnZWNJ = GetGlyphIndex( 0x200C );
512cdf0e10cSrcweir         mbCollectedZW = true;
513cdf0e10cSrcweir     }
514cdf0e10cSrcweir 
515*248a599fSHerbert Dürr     if( !aGlyphId ) // don't hide the NotDef glyph
516cdf0e10cSrcweir         return false;
517*248a599fSHerbert Dürr     if( (aGlyphId == mnZWNJ) || (aGlyphId == mnZWJ) )
518cdf0e10cSrcweir         return true;
519cdf0e10cSrcweir 
520cdf0e10cSrcweir     return false;
521cdf0e10cSrcweir }
522cdf0e10cSrcweir 
523cdf0e10cSrcweir // =======================================================================
524cdf0e10cSrcweir 
ImplServerFontEntry(ImplFontSelectData & rFSD)525cdf0e10cSrcweir ImplServerFontEntry::ImplServerFontEntry( ImplFontSelectData& rFSD )
526cdf0e10cSrcweir :   ImplFontEntry( rFSD )
527cdf0e10cSrcweir ,   mpServerFont( NULL )
528cdf0e10cSrcweir ,   mbGotFontOptions( false )
529cdf0e10cSrcweir ,   mbValidFontOptions( false )
530cdf0e10cSrcweir {}
531cdf0e10cSrcweir 
532cdf0e10cSrcweir // -----------------------------------------------------------------------
533cdf0e10cSrcweir 
~ImplServerFontEntry()534cdf0e10cSrcweir ImplServerFontEntry::~ImplServerFontEntry()
535cdf0e10cSrcweir {
536cdf0e10cSrcweir     // TODO: remove the ServerFont here instead of in the GlyphCache
537cdf0e10cSrcweir }
538cdf0e10cSrcweir 
539cdf0e10cSrcweir // =======================================================================
540cdf0e10cSrcweir 
ExtraKernInfo(sal_IntPtr nFontId)541cdf0e10cSrcweir ExtraKernInfo::ExtraKernInfo( sal_IntPtr nFontId )
542cdf0e10cSrcweir :   mbInitialized( false ),
543cdf0e10cSrcweir     mnFontId( nFontId ),
544cdf0e10cSrcweir     maUnicodeKernPairs( 0 )
545cdf0e10cSrcweir {}
546cdf0e10cSrcweir 
547cdf0e10cSrcweir //--------------------------------------------------------------------------
548cdf0e10cSrcweir 
HasKernPairs() const549cdf0e10cSrcweir bool ExtraKernInfo::HasKernPairs() const
550cdf0e10cSrcweir {
551cdf0e10cSrcweir     if( !mbInitialized )
552cdf0e10cSrcweir         Initialize();
553cdf0e10cSrcweir     return !maUnicodeKernPairs.empty();
554cdf0e10cSrcweir }
555cdf0e10cSrcweir 
556cdf0e10cSrcweir //--------------------------------------------------------------------------
557cdf0e10cSrcweir 
GetUnscaledKernPairs(ImplKernPairData ** ppKernPairs) const558cdf0e10cSrcweir 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 
GetUnscaledKernValue(sal_Unicode cLeft,sal_Unicode cRight) const582cdf0e10cSrcweir 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