kodi
GUIFontCache.h
Go to the documentation of this file.
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 #pragma once
10 
16 #include "utils/ColorUtils.h"
17 #include "utils/TransformMatrix.h"
18 
19 #include <algorithm>
20 #include <cassert>
21 #include <chrono>
22 #include <cstddef>
23 #include <cstring>
24 #include <memory>
25 #include <stdint.h>
26 #include <vector>
27 
28 constexpr float FONT_CACHE_DIST_LIMIT = 0.01f;
29 
30 class CGraphicContext;
31 
32 template<class Position, class Value>
34 class CGUIFontTTF;
35 
36 template<class Position, class Value>
37 class CGUIFontCacheImpl;
38 
39 template<class Position>
41 {
42  Position m_pos;
43  std::vector<UTILS::COLOR::Color>& m_colors;
44  vecText& m_text;
45  uint32_t m_alignment;
46  float m_maxPixelWidth;
47  bool m_scrolling;
48  const TransformMatrix& m_matrix;
49  float m_scaleX;
50  float m_scaleY;
51 
52  CGUIFontCacheKey(Position pos,
53  std::vector<UTILS::COLOR::Color>& colors,
54  vecText& text,
55  uint32_t alignment,
56  float maxPixelWidth,
57  bool scrolling,
58  const TransformMatrix& matrix,
59  float scaleX,
60  float scaleY)
61  : m_pos(pos),
62  m_colors(colors),
63  m_text(text),
64  m_alignment(alignment),
65  m_maxPixelWidth(maxPixelWidth),
66  m_scrolling(scrolling),
67  m_matrix(matrix),
68  m_scaleX(scaleX),
69  m_scaleY(scaleY)
70  {
71  }
72 };
73 
74 template<class Position, class Value>
76 {
77  const CGUIFontCache<Position, Value>& m_cache;
79  TransformMatrix m_matrix;
80  std::chrono::steady_clock::time_point m_lastUsed;
81  Value m_value;
82 
84  const CGUIFontCacheKey<Position>& key,
85  std::chrono::steady_clock::time_point now)
86  : m_cache(cache),
87  m_key(key.m_pos,
88  *new std::vector<UTILS::COLOR::Color>,
89  *new vecText,
90  key.m_alignment,
91  key.m_maxPixelWidth,
92  key.m_scrolling,
93  m_matrix,
94  key.m_scaleX,
95  key.m_scaleY),
96  m_lastUsed(now)
97  {
98  m_key.m_colors.assign(key.m_colors.begin(), key.m_colors.end());
99  m_key.m_text.assign(key.m_text.begin(), key.m_text.end());
100  m_matrix = key.m_matrix;
101  }
102 
104 
105  void Assign(const CGUIFontCacheKey<Position>& key, std::chrono::steady_clock::time_point now);
106 };
107 
108 template<class Position>
110 {
111  size_t operator()(const CGUIFontCacheKey<Position>& key) const
112  {
113  /* Not much effort has gone into choosing this hash function */
114  size_t hash = 0, i;
115  for (i = 0; i < 3 && i < key.m_text.size(); ++i)
116  hash += key.m_text[i];
117  if (key.m_colors.size())
118  hash += key.m_colors[0];
119  hash += static_cast<size_t>(MatrixHashContribution(key)); // horrible
120  return hash;
121  }
122 };
123 
124 template<class Position>
126 {
127  bool operator()(const CGUIFontCacheKey<Position>& a, const CGUIFontCacheKey<Position>& b) const
128  {
129  // clang-format off
130  return a.m_text == b.m_text &&
131  a.m_colors == b.m_colors &&
132  a.m_alignment == b.m_alignment &&
133  a.m_scrolling == b.m_scrolling &&
134  a.m_maxPixelWidth == b.m_maxPixelWidth &&
135  Match(a.m_pos, a.m_matrix, b.m_pos, b.m_matrix, a.m_scrolling) &&
136  a.m_scaleX == b.m_scaleX &&
137  a.m_scaleY == b.m_scaleY;
138  // clang-format on
139  }
140 };
141 
142 
143 template<class Position, class Value>
144 class CGUIFontCache
145 {
146  std::unique_ptr<CGUIFontCacheImpl<Position, Value>> m_impl;
147 
149  const CGUIFontCache<Position, Value>& operator=(const CGUIFontCache<Position, Value>&) = delete;
150 
151 public:
152  const CGUIFontTTF& m_font;
153 
154  explicit CGUIFontCache(CGUIFontTTF& font);
155 
156  ~CGUIFontCache();
157 
158  Value& Lookup(const CGraphicContext& context,
159  Position& pos,
160  const std::vector<UTILS::COLOR::Color>& colors,
161  const vecText& text,
162  uint32_t alignment,
163  float maxPixelWidth,
164  bool scrolling,
165  std::chrono::steady_clock::time_point now,
166  bool& dirtyCache);
167  void Flush();
168 };
169 
171 {
172  float m_x;
173  float m_y;
174  CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {}
175  void UpdateWithOffsets(const CGUIFontCacheStaticPosition& cached, bool scrolling) {}
176 };
177 
178 struct CGUIFontCacheStaticValue : public std::shared_ptr<std::vector<SVertex>>
179 {
180  void clear()
181  {
182  if (*this)
183  (*this)->clear();
184  }
185 };
186 
187 inline bool Match(const CGUIFontCacheStaticPosition& a,
188  const TransformMatrix& a_m,
190  const TransformMatrix& b_m,
191  bool scrolling)
192 {
193  return a.m_x == b.m_x && a.m_y == b.m_y && a_m == b_m;
194 }
195 
196 inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheStaticPosition>& a)
197 {
198  /* Ensure horizontally translated versions end up in different buckets */
199  return a.m_matrix.m[0][3];
200 }
201 
203 {
204  float m_x;
205  float m_y;
206  float m_z;
207  CGUIFontCacheDynamicPosition() = default;
208  CGUIFontCacheDynamicPosition(float x, float y, float z) : m_x(x), m_y(y), m_z(z) {}
209  void UpdateWithOffsets(const CGUIFontCacheDynamicPosition& cached, bool scrolling)
210  {
211  if (scrolling)
212  m_x = m_x - cached.m_x;
213  else
214  m_x = floorf(m_x - cached.m_x + FONT_CACHE_DIST_LIMIT);
215  m_y = floorf(m_y - cached.m_y + FONT_CACHE_DIST_LIMIT);
216  m_z = floorf(m_z - cached.m_z + FONT_CACHE_DIST_LIMIT);
217  }
218 };
219 
221 {
222 #if defined(HAS_GL) || defined(HAS_GLES)
223  typedef unsigned int BufferHandleType;
224 #define BUFFER_HANDLE_INIT 0
225 #elif defined(HAS_DX)
226  typedef void* BufferHandleType;
227 #define BUFFER_HANDLE_INIT nullptr
228 #endif
229  BufferHandleType bufferHandle = BUFFER_HANDLE_INIT; // this is really a GLuint
230  size_t size = 0;
231  CVertexBuffer() : m_font(nullptr) {}
232  CVertexBuffer(BufferHandleType bufferHandle, size_t size, const CGUIFontTTF* font)
233  : bufferHandle(bufferHandle), size(size), m_font(font)
234  {
235  }
236  CVertexBuffer(const CVertexBuffer& other)
237  : bufferHandle(other.bufferHandle), size(other.size), m_font(other.m_font)
238  {
239  /* In practice, the copy constructor is only called before a vertex buffer
240  * has been attached. If this should ever change, we'll need another support
241  * function in GUIFontTTFGL/DX to duplicate a buffer, given its handle. */
242  assert(other.bufferHandle == 0);
243  }
244  CVertexBuffer& operator=(CVertexBuffer& other)
245  {
246  /* This is used with move-assignment semantics for initialising the object in the font cache */
247  assert(bufferHandle == 0);
248  bufferHandle = other.bufferHandle;
249  other.bufferHandle = 0;
250  size = other.size;
251  m_font = other.m_font;
252  return *this;
253  }
254  void clear();
255 
256 private:
257  const CGUIFontTTF* m_font;
258 };
259 
261 
262 inline bool Match(const CGUIFontCacheDynamicPosition& a,
263  const TransformMatrix& a_m,
265  const TransformMatrix& b_m,
266  bool scrolling)
267 {
268  float diffX = a.m_x - b.m_x + FONT_CACHE_DIST_LIMIT;
269  float diffY = a.m_y - b.m_y + FONT_CACHE_DIST_LIMIT;
270  float diffZ = a.m_z - b.m_z + FONT_CACHE_DIST_LIMIT;
271  // clang-format off
272  return (scrolling ||
273  diffX - floorf(diffX) < 2 * FONT_CACHE_DIST_LIMIT) &&
274  diffY - floorf(diffY) < 2 * FONT_CACHE_DIST_LIMIT &&
275  diffZ - floorf(diffZ) < 2 * FONT_CACHE_DIST_LIMIT &&
276  a_m.m[0][0] == b_m.m[0][0] &&
277  a_m.m[1][1] == b_m.m[1][1] &&
278  a_m.m[2][2] == b_m.m[2][2];
279  // clang-format on
280  // We already know the first 3 columns of both matrices are diagonal, so no need to check the other elements
281 }
282 
283 inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheDynamicPosition>& a)
284 {
285  return 0;
286 }
Definition: GUIFontCache.h:178
Definition: GUIFontTTF.h:76
Definition: GUIFontCache.h:125
Definition: GUIFontCache.h:33
Definition: TransformMatrix.h:25
Definition: GUIFontCache.h:109
Definition: GUIFontCache.h:170
Definition: LibInputPointer.h:13
Definition: GUIFontCache.h:220
Definition: GUIFontCache.h:40
Definition: GUIFontCache.h:75
Definition: GUIFontCache.cpp:23
Definition: GUIFontCache.h:202
Definition: GraphicContext.h:60
Definition: cache.py:1