1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "GUIFontTTF.h"
10 #include "windowing/GraphicContext.h"
11
12 #include <stdint.h>
13 #include <vector>
14
15 template<class Position, class Value>
16 class CGUIFontCacheImpl
17 {
18 struct EntryList
19 {
20 using HashMap = std::multimap<size_t, CGUIFontCacheEntry<Position, Value>*>;
21 using HashIter = typename HashMap::iterator;
22 using AgeMap = std::multimap<size_t, HashIter>;
23
~EntryListCGUIFontCacheImpl::EntryList24 ~EntryList()
25 {
26 Flush();
27 }
InsertCGUIFontCacheImpl::EntryList28 HashIter Insert(size_t hash, CGUIFontCacheEntry<Position, Value> *v)
29 {
30 auto r (hashMap.insert(typename HashMap::value_type(hash, v)));
31 if (r->second)
32 ageMap.insert(typename AgeMap::value_type(r->second->m_lastUsedMillis, r));
33 return r;
34 }
FlushCGUIFontCacheImpl::EntryList35 void Flush()
36 {
37 ageMap.clear();
38 for (auto it = hashMap.begin(); it != hashMap.end(); ++it)
39 delete(it->second);
40 hashMap.clear();
41 }
FindKeyCGUIFontCacheImpl::EntryList42 typename HashMap::iterator FindKey(CGUIFontCacheKey<Position> key)
43 {
44 CGUIFontCacheHash<Position> hashGen;
45 CGUIFontCacheKeysMatch<Position> keyMatch;
46 auto range = hashMap.equal_range(hashGen(key));
47 for (auto ret = range.first; ret != range.second; ++ret)
48 {
49 if (keyMatch(ret->second->m_key, key))
50 {
51 return ret;
52 }
53 }
54 return hashMap.end();
55 }
UpdateAgeCGUIFontCacheImpl::EntryList56 void UpdateAge(HashIter it, size_t millis)
57 {
58 auto range = ageMap.equal_range(it->second->m_lastUsedMillis);
59 for (auto ageit = range.first; ageit != range.second; ++ageit)
60 {
61 if (ageit->second == it)
62 {
63 ageMap.erase(ageit);
64 ageMap.insert(typename AgeMap::value_type(millis, it));
65 it->second->m_lastUsedMillis = millis;
66 return;
67 }
68 }
69 }
70
71 HashMap hashMap;
72 AgeMap ageMap;
73 };
74
75 EntryList m_list;
76 CGUIFontCache<Position, Value> *m_parent;
77
78 public:
79
CGUIFontCacheImpl(CGUIFontCache<Position,Value> * parent)80 explicit CGUIFontCacheImpl(CGUIFontCache<Position, Value>* parent) : m_parent(parent) {}
81 Value &Lookup(Position &pos,
82 const std::vector<UTILS::Color> &colors, const vecText &text,
83 uint32_t alignment, float maxPixelWidth,
84 bool scrolling,
85 unsigned int nowMillis, bool &dirtyCache);
86 void Flush();
87 };
88
89 template<class Position, class Value>
~CGUIFontCacheEntry()90 CGUIFontCacheEntry<Position, Value>::~CGUIFontCacheEntry()
91 {
92 delete &m_key.m_colors;
93 delete &m_key.m_text;
94 m_value.clear();
95 }
96
97 template<class Position, class Value>
Assign(const CGUIFontCacheKey<Position> & key,unsigned int nowMillis)98 void CGUIFontCacheEntry<Position, Value>::Assign(const CGUIFontCacheKey<Position> &key, unsigned int nowMillis)
99 {
100 m_key.m_pos = key.m_pos;
101 m_key.m_colors.assign(key.m_colors.begin(), key.m_colors.end());
102 m_key.m_text.assign(key.m_text.begin(), key.m_text.end());
103 m_key.m_alignment = key.m_alignment;
104 m_key.m_maxPixelWidth = key.m_maxPixelWidth;
105 m_key.m_scrolling = key.m_scrolling;
106 m_matrix = key.m_matrix;
107 m_key.m_scaleX = key.m_scaleX;
108 m_key.m_scaleY = key.m_scaleY;
109 m_lastUsedMillis = nowMillis;
110 m_value.clear();
111 }
112
113 template<class Position, class Value>
CGUIFontCache(CGUIFontTTF & font)114 CGUIFontCache<Position, Value>::CGUIFontCache(CGUIFontTTF& font)
115 : m_impl(new CGUIFontCacheImpl<Position, Value>(this)), m_font(font)
116 {
117 }
118
119 template<class Position, class Value>
~CGUIFontCache()120 CGUIFontCache<Position, Value>::~CGUIFontCache()
121 {
122 delete m_impl;
123 }
124
125 template<class Position, class Value>
Lookup(Position & pos,const std::vector<UTILS::Color> & colors,const vecText & text,uint32_t alignment,float maxPixelWidth,bool scrolling,unsigned int nowMillis,bool & dirtyCache)126 Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
127 const std::vector<UTILS::Color> &colors, const vecText &text,
128 uint32_t alignment, float maxPixelWidth,
129 bool scrolling,
130 unsigned int nowMillis, bool &dirtyCache)
131 {
132 if (m_impl == nullptr)
133 m_impl = new CGUIFontCacheImpl<Position, Value>(this);
134
135 return m_impl->Lookup(pos, colors, text, alignment, maxPixelWidth, scrolling, nowMillis, dirtyCache);
136 }
137
138 template<class Position, class Value>
Lookup(Position & pos,const std::vector<UTILS::Color> & colors,const vecText & text,uint32_t alignment,float maxPixelWidth,bool scrolling,unsigned int nowMillis,bool & dirtyCache)139 Value &CGUIFontCacheImpl<Position, Value>::Lookup(Position &pos,
140 const std::vector<UTILS::Color> &colors, const vecText &text,
141 uint32_t alignment, float maxPixelWidth,
142 bool scrolling,
143 unsigned int nowMillis, bool &dirtyCache)
144 {
145 const CGUIFontCacheKey<Position> key(pos,
146 const_cast<std::vector<UTILS::Color> &>(colors), const_cast<vecText &>(text),
147 alignment, maxPixelWidth,
148 scrolling, CServiceBroker::GetWinSystem()->GetGfxContext().GetGUIMatrix(),
149 CServiceBroker::GetWinSystem()->GetGfxContext().GetGUIScaleX(), CServiceBroker::GetWinSystem()->GetGfxContext().GetGUIScaleY());
150
151 auto i = m_list.FindKey(key);
152 if (i == m_list.hashMap.end())
153 {
154 // Cache miss
155 dirtyCache = true;
156 CGUIFontCacheEntry<Position, Value> *entry = nullptr;
157 if (!m_list.ageMap.empty() && (nowMillis - m_list.ageMap.begin()->first) > FONT_CACHE_TIME_LIMIT)
158 {
159 entry = m_list.ageMap.begin()->second->second;
160 m_list.hashMap.erase(m_list.ageMap.begin()->second);
161 m_list.ageMap.erase(m_list.ageMap.begin());
162 }
163
164 // add new entry
165 CGUIFontCacheHash<Position> hashgen;
166 if (!entry)
167 entry = new CGUIFontCacheEntry<Position, Value>(*m_parent, key, nowMillis);
168 else
169 entry->Assign(key, nowMillis);
170 return m_list.Insert(hashgen(key), entry)->second->m_value;
171 }
172 else
173 {
174 // Cache hit
175 // Update the translation arguments so that they hold the offset to apply
176 // to the cached values (but only in the dynamic case)
177 pos.UpdateWithOffsets(i->second->m_key.m_pos, scrolling);
178
179 // Update time in entry and move to the back of the list
180 m_list.UpdateAge(i, nowMillis);
181
182 dirtyCache = false;
183 return i->second->m_value;
184 }
185 }
186
187 template<class Position, class Value>
Flush()188 void CGUIFontCache<Position, Value>::Flush()
189 {
190 m_impl->Flush();
191 }
192
193 template<class Position, class Value>
Flush()194 void CGUIFontCacheImpl<Position, Value>::Flush()
195 {
196 m_list.Flush();
197 }
198
199 template CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::CGUIFontCache(
200 CGUIFontTTF& font);
201 template CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::~CGUIFontCache();
202 template CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::~CGUIFontCacheEntry();
203 template CGUIFontCacheStaticValue &CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Lookup(CGUIFontCacheStaticPosition &, const std::vector<UTILS::Color> &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
204 template void CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Flush();
205
206 template CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::CGUIFontCache(
207 CGUIFontTTF& font);
208 template CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::~CGUIFontCache();
209 template CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::~CGUIFontCacheEntry();
210 template CGUIFontCacheDynamicValue &CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Lookup(CGUIFontCacheDynamicPosition &, const std::vector<UTILS::Color> &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
211 template void CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Flush();
212
clear()213 void CVertexBuffer::clear()
214 {
215 if (m_font != NULL)
216 m_font->DestroyVertexBuffer(*this);
217 }
218