1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <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)
37 GlyphCache::~GlyphCache()
42 void GlyphCache::ClearFontCache()
44 for (auto &aFontPair
: maFontList
)
45 static_cast<FreetypeFontInstance
*>(aFontPair
.first
.get())->SetFreetypeFont(nullptr);
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();
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
)
79 OString aFeatName
= OUStringToOString( rFontSelData
.maTargetName
, RTL_TEXTENCODING_UTF8
);
80 nFontId
^= aFeatName
.hashCode();
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
));
94 bool GlyphCache::IFSD_Equal::operator()(const rtl::Reference
<LogicalFontInstance
>& rAFontInstance
,
95 const rtl::Reference
<LogicalFontInstance
>& rBFontInstance
) const
97 if (!rAFontInstance
->GetFontCache() || !rBFontInstance
->GetFontCache())
101 if (GetFontId(*rAFontInstance
) != GetFontId(*rBFontInstance
))
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
) )
114 if( (rA
.GetItalic() != rB
.GetItalic())
115 || (rA
.GetWeight() != rB
.GetWeight()) )
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
)
126 if (rA
.meLanguage
!= rB
.meLanguage
)
128 // check for features
129 if ((rA
.maTargetName
.indexOf(FontSelectPattern::FEAT_PREFIX
)
131 rB
.maTargetName
.indexOf(FontSelectPattern::FEAT_PREFIX
)
132 != -1) && rA
.maTargetName
!= rB
.maTargetName
)
135 if (rA
.mbEmbolden
!= rB
.mbEmbolden
)
138 if (rA
.maItalicMatrix
!= rB
.maItalicMatrix
)
144 GlyphCache
& GlyphCache::GetInstance()
146 GenericUnixSalData
* const pSalData(GetGenericUnixSalData());
148 return *pSalData
->GetGlyphCache();
151 FreetypeFont
* GlyphCache::CacheFont(LogicalFontInstance
* pFontInstance
)
153 // a serverfont request has a fontid > 0
154 if (GetFontId(*pFontInstance
) <= 0)
157 FontList::iterator it
= maFontList
.find(pFontInstance
);
158 if( it
!= maFontList
.end() )
160 FreetypeFont
* pFound
= it
->second
.get();
166 // font not cached yet => create new font item
167 FreetypeFont
* pNew
= CreateFont(pFontInstance
);
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
;
183 pNew
->mpNextGCFont
= mpCurrentGCFont
;
184 pNew
->mpPrevGCFont
= mpCurrentGCFont
->mpPrevGCFont
;
185 pNew
->mpPrevGCFont
->mpNextGCFont
= pNew
;
186 mpCurrentGCFont
->mpPrevGCFont
= pNew
;
193 void GlyphCache::UncacheFont( FreetypeFont
& rFreetypeFont
)
195 if( (rFreetypeFont
.Release() <= 0) && (gnMaxSize
<= mnBytesUsed
) )
197 mpCurrentGCFont
= &rFreetypeFont
;
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
)
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" );
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
)
272 FreetypeFontInstance::~FreetypeFontInstance()
276 static hb_blob_t
* getFontTable(hb_face_t
* /*face*/, hb_tag_t nTableTag
, void* pUserData
)
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);
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
);
302 bool FreetypeFontInstance::ImplGetGlyphBoundRect(sal_GlyphId nId
, tools::Rectangle
& rRect
, bool bVertical
) const
304 assert(mpFreetypeFont
);
307 return mpFreetypeFont
->GetGlyphBoundRect(nId
, rRect
, bVertical
);
310 bool FreetypeFontInstance::GetGlyphOutline(sal_GlyphId nId
, basegfx::B2DPolyPolygon
& rPoly
, bool bVertical
) const
312 assert(mpFreetypeFont
);
315 return mpFreetypeFont
->GetGlyphOutline(nId
, rPoly
, bVertical
);
318 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */