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