summaryrefslogtreecommitdiffstats
path: root/xbmc/guilib/GUIFontCache.h
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/guilib/GUIFontCache.h')
-rw-r--r--xbmc/guilib/GUIFontCache.h286
1 files changed, 286 insertions, 0 deletions
diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
new file mode 100644
index 0000000..8a967fa
--- /dev/null
+++ b/xbmc/guilib/GUIFontCache.h
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+/*!
+\file GUIFontCache.h
+\brief
+*/
+
+#include "utils/ColorUtils.h"
+#include "utils/TransformMatrix.h"
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <cstring>
+#include <memory>
+#include <stdint.h>
+#include <vector>
+
+constexpr float FONT_CACHE_DIST_LIMIT = 0.01f;
+
+class CGraphicContext;
+
+template<class Position, class Value>
+class CGUIFontCache;
+class CGUIFontTTF;
+
+template<class Position, class Value>
+class CGUIFontCacheImpl;
+
+template<class Position>
+struct CGUIFontCacheKey
+{
+ Position m_pos;
+ std::vector<UTILS::COLOR::Color>& m_colors;
+ vecText& m_text;
+ uint32_t m_alignment;
+ float m_maxPixelWidth;
+ bool m_scrolling;
+ const TransformMatrix& m_matrix;
+ float m_scaleX;
+ float m_scaleY;
+
+ CGUIFontCacheKey(Position pos,
+ std::vector<UTILS::COLOR::Color>& colors,
+ vecText& text,
+ uint32_t alignment,
+ float maxPixelWidth,
+ bool scrolling,
+ const TransformMatrix& matrix,
+ float scaleX,
+ float scaleY)
+ : m_pos(pos),
+ m_colors(colors),
+ m_text(text),
+ m_alignment(alignment),
+ m_maxPixelWidth(maxPixelWidth),
+ m_scrolling(scrolling),
+ m_matrix(matrix),
+ m_scaleX(scaleX),
+ m_scaleY(scaleY)
+ {
+ }
+};
+
+template<class Position, class Value>
+struct CGUIFontCacheEntry
+{
+ const CGUIFontCache<Position, Value>& m_cache;
+ CGUIFontCacheKey<Position> m_key;
+ TransformMatrix m_matrix;
+ std::chrono::steady_clock::time_point m_lastUsed;
+ Value m_value;
+
+ CGUIFontCacheEntry(const CGUIFontCache<Position, Value>& cache,
+ const CGUIFontCacheKey<Position>& key,
+ std::chrono::steady_clock::time_point now)
+ : m_cache(cache),
+ m_key(key.m_pos,
+ *new std::vector<UTILS::COLOR::Color>,
+ *new vecText,
+ key.m_alignment,
+ key.m_maxPixelWidth,
+ key.m_scrolling,
+ m_matrix,
+ key.m_scaleX,
+ key.m_scaleY),
+ m_lastUsed(now)
+ {
+ m_key.m_colors.assign(key.m_colors.begin(), key.m_colors.end());
+ m_key.m_text.assign(key.m_text.begin(), key.m_text.end());
+ m_matrix = key.m_matrix;
+ }
+
+ ~CGUIFontCacheEntry();
+
+ void Assign(const CGUIFontCacheKey<Position>& key, std::chrono::steady_clock::time_point now);
+};
+
+template<class Position>
+struct CGUIFontCacheHash
+{
+ size_t operator()(const CGUIFontCacheKey<Position>& key) const
+ {
+ /* Not much effort has gone into choosing this hash function */
+ size_t hash = 0, i;
+ for (i = 0; i < 3 && i < key.m_text.size(); ++i)
+ hash += key.m_text[i];
+ if (key.m_colors.size())
+ hash += key.m_colors[0];
+ hash += static_cast<size_t>(MatrixHashContribution(key)); // horrible
+ return hash;
+ }
+};
+
+template<class Position>
+struct CGUIFontCacheKeysMatch
+{
+ bool operator()(const CGUIFontCacheKey<Position>& a, const CGUIFontCacheKey<Position>& b) const
+ {
+ // clang-format off
+ return a.m_text == b.m_text &&
+ a.m_colors == b.m_colors &&
+ a.m_alignment == b.m_alignment &&
+ a.m_scrolling == b.m_scrolling &&
+ a.m_maxPixelWidth == b.m_maxPixelWidth &&
+ Match(a.m_pos, a.m_matrix, b.m_pos, b.m_matrix, a.m_scrolling) &&
+ a.m_scaleX == b.m_scaleX &&
+ a.m_scaleY == b.m_scaleY;
+ // clang-format on
+ }
+};
+
+
+template<class Position, class Value>
+class CGUIFontCache
+{
+ std::unique_ptr<CGUIFontCacheImpl<Position, Value>> m_impl;
+
+ CGUIFontCache(const CGUIFontCache<Position, Value>&) = delete;
+ const CGUIFontCache<Position, Value>& operator=(const CGUIFontCache<Position, Value>&) = delete;
+
+public:
+ const CGUIFontTTF& m_font;
+
+ explicit CGUIFontCache(CGUIFontTTF& font);
+
+ ~CGUIFontCache();
+
+ Value& Lookup(const CGraphicContext& context,
+ Position& pos,
+ const std::vector<UTILS::COLOR::Color>& colors,
+ const vecText& text,
+ uint32_t alignment,
+ float maxPixelWidth,
+ bool scrolling,
+ std::chrono::steady_clock::time_point now,
+ bool& dirtyCache);
+ void Flush();
+};
+
+struct CGUIFontCacheStaticPosition
+{
+ float m_x;
+ float m_y;
+ CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {}
+ void UpdateWithOffsets(const CGUIFontCacheStaticPosition& cached, bool scrolling) {}
+};
+
+struct CGUIFontCacheStaticValue : public std::shared_ptr<std::vector<SVertex>>
+{
+ void clear()
+ {
+ if (*this)
+ (*this)->clear();
+ }
+};
+
+inline bool Match(const CGUIFontCacheStaticPosition& a,
+ const TransformMatrix& a_m,
+ const CGUIFontCacheStaticPosition& b,
+ const TransformMatrix& b_m,
+ bool scrolling)
+{
+ return a.m_x == b.m_x && a.m_y == b.m_y && a_m == b_m;
+}
+
+inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheStaticPosition>& a)
+{
+ /* Ensure horizontally translated versions end up in different buckets */
+ return a.m_matrix.m[0][3];
+}
+
+struct CGUIFontCacheDynamicPosition
+{
+ float m_x;
+ float m_y;
+ float m_z;
+ CGUIFontCacheDynamicPosition() = default;
+ CGUIFontCacheDynamicPosition(float x, float y, float z) : m_x(x), m_y(y), m_z(z) {}
+ void UpdateWithOffsets(const CGUIFontCacheDynamicPosition& cached, bool scrolling)
+ {
+ if (scrolling)
+ m_x = m_x - cached.m_x;
+ else
+ m_x = floorf(m_x - cached.m_x + FONT_CACHE_DIST_LIMIT);
+ m_y = floorf(m_y - cached.m_y + FONT_CACHE_DIST_LIMIT);
+ m_z = floorf(m_z - cached.m_z + FONT_CACHE_DIST_LIMIT);
+ }
+};
+
+struct CVertexBuffer
+{
+#if defined(HAS_GL) || defined(HAS_GLES)
+ typedef unsigned int BufferHandleType;
+#define BUFFER_HANDLE_INIT 0
+#elif defined(HAS_DX)
+ typedef void* BufferHandleType;
+#define BUFFER_HANDLE_INIT nullptr
+#endif
+ BufferHandleType bufferHandle = BUFFER_HANDLE_INIT; // this is really a GLuint
+ size_t size = 0;
+ CVertexBuffer() : m_font(nullptr) {}
+ CVertexBuffer(BufferHandleType bufferHandle, size_t size, const CGUIFontTTF* font)
+ : bufferHandle(bufferHandle), size(size), m_font(font)
+ {
+ }
+ CVertexBuffer(const CVertexBuffer& other)
+ : bufferHandle(other.bufferHandle), size(other.size), m_font(other.m_font)
+ {
+ /* In practice, the copy constructor is only called before a vertex buffer
+ * has been attached. If this should ever change, we'll need another support
+ * function in GUIFontTTFGL/DX to duplicate a buffer, given its handle. */
+ assert(other.bufferHandle == 0);
+ }
+ CVertexBuffer& operator=(CVertexBuffer& other)
+ {
+ /* This is used with move-assignment semantics for initialising the object in the font cache */
+ assert(bufferHandle == 0);
+ bufferHandle = other.bufferHandle;
+ other.bufferHandle = 0;
+ size = other.size;
+ m_font = other.m_font;
+ return *this;
+ }
+ void clear();
+
+private:
+ const CGUIFontTTF* m_font;
+};
+
+typedef CVertexBuffer CGUIFontCacheDynamicValue;
+
+inline bool Match(const CGUIFontCacheDynamicPosition& a,
+ const TransformMatrix& a_m,
+ const CGUIFontCacheDynamicPosition& b,
+ const TransformMatrix& b_m,
+ bool scrolling)
+{
+ float diffX = a.m_x - b.m_x + FONT_CACHE_DIST_LIMIT;
+ float diffY = a.m_y - b.m_y + FONT_CACHE_DIST_LIMIT;
+ float diffZ = a.m_z - b.m_z + FONT_CACHE_DIST_LIMIT;
+ // clang-format off
+ return (scrolling ||
+ diffX - floorf(diffX) < 2 * FONT_CACHE_DIST_LIMIT) &&
+ diffY - floorf(diffY) < 2 * FONT_CACHE_DIST_LIMIT &&
+ diffZ - floorf(diffZ) < 2 * FONT_CACHE_DIST_LIMIT &&
+ a_m.m[0][0] == b_m.m[0][0] &&
+ a_m.m[1][1] == b_m.m[1][1] &&
+ a_m.m[2][2] == b_m.m[2][2];
+ // clang-format on
+ // We already know the first 3 columns of both matrices are diagonal, so no need to check the other elements
+}
+
+inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheDynamicPosition>& a)
+{
+ return 0;
+}