Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / unx / generic / glyphs / glyphcache.cxx
blob46be26d38971d06c925621759d138fdf18e8c3c9
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 .
20 #include <stdlib.h>
21 #include <unx/freetype_glyphcache.hxx>
22 #include <unx/gendata.hxx>
24 #include <fontinstance.hxx>
26 #include <rtl/ustring.hxx>
27 #include <sal/log.hxx>
29 GlyphCache::GlyphCache()
30 : mnBytesUsed(sizeof(GlyphCache)),
31 mpCurrentGCFont(nullptr)
32 , m_nMaxFontId(0)
34 InitFreetype();
37 GlyphCache::~GlyphCache()
39 ClearFontCache();
42 void GlyphCache::ClearFontCache()
44 for (auto &aFontPair : maFontList)
45 static_cast<FreetypeFontInstance*>(aFontPair.first.get())->SetFreetypeFont(nullptr);
46 maFontList.clear();
47 mpCurrentGCFont = nullptr;
48 m_aFontInfoList.clear();
51 void GlyphCache::ClearFontOptions()
53 for (auto const& font : maFontList)
55 FreetypeFont* pFreetypeFont = font.second.get();
56 // free demand-loaded FontConfig related data
57 pFreetypeFont->ClearFontOptions();
61 static sal_IntPtr GetFontId(const LogicalFontInstance& rFontInstance)
63 if (rFontInstance.GetFontFace())
64 return rFontInstance.GetFontFace()->GetFontId();
65 return 0;
68 inline
69 size_t GlyphCache::IFSD_Hash::operator()(const rtl::Reference<LogicalFontInstance>& rFontInstance) const
71 // TODO: is it worth to improve this hash function?
72 sal_uIntPtr nFontId = GetFontId(*rFontInstance);
74 const FontSelectPattern& rFontSelData = rFontInstance->GetFontSelectPattern();
76 if (rFontSelData.maTargetName.indexOf(FontSelectPattern::FEAT_PREFIX)
77 != -1)
79 OString aFeatName = OUStringToOString( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
80 nFontId ^= aFeatName.hashCode();
83 std::size_t seed = 0;
84 boost::hash_combine(seed, nFontId);
85 boost::hash_combine(seed, rFontSelData.mnHeight);
86 boost::hash_combine(seed, rFontSelData.mnOrientation);
87 boost::hash_combine(seed, size_t(rFontSelData.mbVertical));
88 boost::hash_combine(seed, rFontSelData.GetItalic());
89 boost::hash_combine(seed, rFontSelData.GetWeight());
90 boost::hash_combine(seed, static_cast<sal_uInt16>(rFontSelData.meLanguage));
91 return seed;
94 bool GlyphCache::IFSD_Equal::operator()(const rtl::Reference<LogicalFontInstance>& rAFontInstance,
95 const rtl::Reference<LogicalFontInstance>& rBFontInstance) const
97 if (!rAFontInstance->GetFontCache() || !rBFontInstance->GetFontCache())
98 return false;
100 // check font ids
101 if (GetFontId(*rAFontInstance) != GetFontId(*rBFontInstance))
102 return false;
104 const FontSelectPattern& rA = rAFontInstance->GetFontSelectPattern();
105 const FontSelectPattern& rB = rBFontInstance->GetFontSelectPattern();
107 // compare with the requested metrics
108 if( (rA.mnHeight != rB.mnHeight)
109 || (rA.mnOrientation != rB.mnOrientation)
110 || (rA.mbVertical != rB.mbVertical)
111 || (rA.mbNonAntialiased != rB.mbNonAntialiased) )
112 return false;
114 if( (rA.GetItalic() != rB.GetItalic())
115 || (rA.GetWeight() != rB.GetWeight()) )
116 return false;
118 // NOTE: ignoring meFamily deliberately
120 // compare with the requested width, allow default width
121 int nAWidth = rA.mnWidth != 0 ? rA.mnWidth : rA.mnHeight;
122 int nBWidth = rB.mnWidth != 0 ? rB.mnWidth : rB.mnHeight;
123 if( nAWidth != nBWidth )
124 return false;
126 if (rA.meLanguage != rB.meLanguage)
127 return false;
128 // check for features
129 if ((rA.maTargetName.indexOf(FontSelectPattern::FEAT_PREFIX)
130 != -1 ||
131 rB.maTargetName.indexOf(FontSelectPattern::FEAT_PREFIX)
132 != -1) && rA.maTargetName != rB.maTargetName)
133 return false;
135 if (rA.mbEmbolden != rB.mbEmbolden)
136 return false;
138 if (rA.maItalicMatrix != rB.maItalicMatrix)
139 return false;
141 return true;
144 GlyphCache& GlyphCache::GetInstance()
146 GenericUnixSalData* const pSalData(GetGenericUnixSalData());
147 assert(pSalData);
148 return *pSalData->GetGlyphCache();
151 FreetypeFont* GlyphCache::CacheFont(LogicalFontInstance* pFontInstance)
153 // a serverfont request has a fontid > 0
154 if (GetFontId(*pFontInstance) <= 0)
155 return nullptr;
157 FontList::iterator it = maFontList.find(pFontInstance);
158 if( it != maFontList.end() )
160 FreetypeFont* pFound = it->second.get();
161 assert(pFound);
162 pFound->AddRef();
163 return pFound;
166 // font not cached yet => create new font item
167 FreetypeFont* pNew = CreateFont(pFontInstance);
169 if( pNew )
171 maFontList[pFontInstance].reset(pNew);
172 mnBytesUsed += pNew->GetByteCount();
174 // enable garbage collection for new font
175 if( !mpCurrentGCFont )
177 mpCurrentGCFont = pNew;
178 pNew->mpNextGCFont = pNew;
179 pNew->mpPrevGCFont = pNew;
181 else
183 pNew->mpNextGCFont = mpCurrentGCFont;
184 pNew->mpPrevGCFont = mpCurrentGCFont->mpPrevGCFont;
185 pNew->mpPrevGCFont->mpNextGCFont = pNew;
186 mpCurrentGCFont->mpPrevGCFont = pNew;
190 return pNew;
193 void GlyphCache::UncacheFont( FreetypeFont& rFreetypeFont )
195 if( (rFreetypeFont.Release() <= 0) && (gnMaxSize <= mnBytesUsed) )
197 mpCurrentGCFont = &rFreetypeFont;
198 GarbageCollect();
202 void GlyphCache::GarbageCollect()
204 // when current GC font has been destroyed get another one
205 if( !mpCurrentGCFont )
207 FontList::iterator it = maFontList.begin();
208 if( it != maFontList.end() )
209 mpCurrentGCFont = it->second.get();
212 // unless there is no other font to collect
213 if( !mpCurrentGCFont )
214 return;
216 // prepare advance to next font for garbage collection
217 FreetypeFont* const pFreetypeFont = mpCurrentGCFont;
218 mpCurrentGCFont = pFreetypeFont->mpNextGCFont;
220 if( (pFreetypeFont != mpCurrentGCFont) // no other fonts
221 && (pFreetypeFont->GetRefCount() <= 0) ) // font still used
223 SAL_WARN_IF( (pFreetypeFont->GetRefCount() != 0), "vcl",
224 "GlyphCache::GC detected RefCount underflow" );
226 // free all pFreetypeFont related data
227 if( pFreetypeFont == mpCurrentGCFont )
228 mpCurrentGCFont = nullptr;
229 mnBytesUsed -= pFreetypeFont->GetByteCount();
231 // remove font from list of garbage collected fonts
232 if( pFreetypeFont->mpPrevGCFont )
233 pFreetypeFont->mpPrevGCFont->mpNextGCFont = pFreetypeFont->mpNextGCFont;
234 if( pFreetypeFont->mpNextGCFont )
235 pFreetypeFont->mpNextGCFont->mpPrevGCFont = pFreetypeFont->mpPrevGCFont;
236 if( pFreetypeFont == mpCurrentGCFont )
237 mpCurrentGCFont = nullptr;
239 maFontList.erase(pFreetypeFont->GetFontInstance());
243 void FreetypeFont::ReleaseFromGarbageCollect()
245 // remove from GC list
246 FreetypeFont* pPrev = mpPrevGCFont;
247 FreetypeFont* pNext = mpNextGCFont;
248 if( pPrev ) pPrev->mpNextGCFont = pNext;
249 if( pNext ) pNext->mpPrevGCFont = pPrev;
250 mpPrevGCFont = nullptr;
251 mpNextGCFont = nullptr;
254 long FreetypeFont::Release() const
256 SAL_WARN_IF( mnRefCount <= 0, "vcl", "FreetypeFont: RefCount underflow" );
257 return --mnRefCount;
260 FreetypeFontInstance::FreetypeFontInstance(const PhysicalFontFace& rPFF, const FontSelectPattern& rFSP)
261 : LogicalFontInstance(rPFF, rFSP)
262 , mpFreetypeFont(nullptr)
265 void FreetypeFontInstance::SetFreetypeFont(FreetypeFont* p)
267 if (p == mpFreetypeFont)
268 return;
269 mpFreetypeFont = p;
272 FreetypeFontInstance::~FreetypeFontInstance()
276 static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData)
278 char pTagName[5];
279 LogicalFontInstance::DecodeOpenTypeTag( nTableTag, pTagName );
281 sal_uLong nLength = 0;
282 FreetypeFontInstance* pFontInstance = static_cast<FreetypeFontInstance*>( pUserData );
283 FreetypeFont* pFont = pFontInstance->GetFreetypeFont();
284 const char* pBuffer = reinterpret_cast<const char*>(
285 pFont->GetTable(pTagName, &nLength) );
287 hb_blob_t* pBlob = nullptr;
288 if (pBuffer != nullptr)
289 pBlob = hb_blob_create(pBuffer, nLength, HB_MEMORY_MODE_READONLY, nullptr, nullptr);
291 return pBlob;
294 hb_font_t* FreetypeFontInstance::ImplInitHbFont()
296 hb_font_t* pRet = InitHbFont(hb_face_create_for_tables(getFontTable, this, nullptr));
297 assert(mpFreetypeFont);
298 mpFreetypeFont->SetFontVariationsOnHBFont(pRet);
299 return pRet;
302 bool FreetypeFontInstance::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool bVertical) const
304 assert(mpFreetypeFont);
305 if (!mpFreetypeFont)
306 return false;
307 return mpFreetypeFont->GetGlyphBoundRect(nId, rRect, bVertical);
310 bool FreetypeFontInstance::GetGlyphOutline(sal_GlyphId nId, basegfx::B2DPolyPolygon& rPoly, bool bVertical) const
312 assert(mpFreetypeFont);
313 if (!mpFreetypeFont)
314 return false;
315 return mpFreetypeFont->GetGlyphOutline(nId, rPoly, bVertical);
318 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */