aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Avison <bavison@riscosopen.org>2014-01-15 17:18:38 +0000
committerBen Avison <bavison@riscosopen.org>2015-01-26 14:19:52 +0000
commitc8a899ae026c4ac35340100163c98697cbd39931 (patch)
treea4860ac8c0e7e4f37cb23f79806a6b91e9bfaa44
parent3b29905cc65241cdcc6f3a738a9f6517504b4646 (diff)
Add a cache of font glyph bounding box vertices.
This is implemented as a template because ultimately we will key on different parameters and store values of different types, depending upon whether we have a GLES or non-GLES backend, and for GLES, whether or not the currently applicable transformation matrices permit the use of hardware clipping.
-rw-r--r--Kodi.xcodeproj/project.pbxproj10
-rw-r--r--project/VS2010Express/XBMC.vcxproj4
-rw-r--r--project/VS2010Express/XBMC.vcxproj.filters8
-rw-r--r--xbmc/guilib/GUIFontCache.cpp104
-rw-r--r--xbmc/guilib/GUIFontCache.h225
-rw-r--r--xbmc/guilib/GUIFontTTF.cpp192
-rw-r--r--xbmc/guilib/GUIFontTTF.h5
-rw-r--r--xbmc/guilib/GUIFontTTFGL.cpp1
-rw-r--r--xbmc/guilib/GraphicContext.h1
-rw-r--r--xbmc/guilib/Makefile.in1
-rw-r--r--xbmc/guilib/TransformMatrix.h11
11 files changed, 476 insertions, 86 deletions
diff --git a/Kodi.xcodeproj/project.pbxproj b/Kodi.xcodeproj/project.pbxproj
index 5c1fca1579..f49e86fb22 100644
--- a/Kodi.xcodeproj/project.pbxproj
+++ b/Kodi.xcodeproj/project.pbxproj
@@ -168,6 +168,9 @@
1D638128161E211E003603ED /* PeripheralImon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1D638126161E211E003603ED /* PeripheralImon.cpp */; };
1DAFDB7C16DFDCA7007F8C68 /* PeripheralBusCEC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DAFDB7A16DFDCA7007F8C68 /* PeripheralBusCEC.cpp */; };
1DE0443515828F4B005DDB4D /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DE0443315828F4B005DDB4D /* Exception.cpp */; };
+ 2F4564D51970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; };
+ 2F4564D61970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; };
+ 2F4564D71970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; };
32C631281423A90F00F18420 /* JpegIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32C631261423A90F00F18420 /* JpegIO.cpp */; };
36A9443D15821E2800727135 /* DatabaseUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443B15821E2800727135 /* DatabaseUtils.cpp */; };
36A9444115821E7C00727135 /* SortUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443F15821E7C00727135 /* SortUtils.cpp */; };
@@ -4024,6 +4027,8 @@
1DAFDB7B16DFDCA7007F8C68 /* PeripheralBusCEC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeripheralBusCEC.h; sourceTree = "<group>"; };
1DE0443315828F4B005DDB4D /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Exception.cpp; path = commons/Exception.cpp; sourceTree = "<group>"; };
1DE0443415828F4B005DDB4D /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exception.h; path = commons/Exception.h; sourceTree = "<group>"; };
+ 2F4564D31970129A00396109 /* GUIFontCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIFontCache.cpp; sourceTree = "<group>"; };
+ 2F4564D41970129A00396109 /* GUIFontCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIFontCache.h; sourceTree = "<group>"; };
32C631261423A90F00F18420 /* JpegIO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JpegIO.cpp; sourceTree = "<group>"; };
32C631271423A90F00F18420 /* JpegIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JpegIO.h; sourceTree = "<group>"; };
36A9443B15821E2800727135 /* DatabaseUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatabaseUtils.cpp; sourceTree = "<group>"; };
@@ -6543,6 +6548,8 @@
18B7C7101294222D009E7A26 /* GUIFixedListContainer.h */,
18B7C76B1294222E009E7A26 /* GUIFont.cpp */,
18B7C7111294222D009E7A26 /* GUIFont.h */,
+ 2F4564D31970129A00396109 /* GUIFontCache.cpp */,
+ 2F4564D41970129A00396109 /* GUIFontCache.h */,
18B7C76C1294222E009E7A26 /* GUIFontManager.cpp */,
18B7C7121294222D009E7A26 /* GUIFontManager.h */,
18B7C76D1294222E009E7A26 /* GUIFontTTF.cpp */,
@@ -11055,6 +11062,7 @@
7C5608C70F1754930056433A /* ExternalPlayer.cpp in Sources */,
F584E12E0F257C5100DB26A5 /* HTTPDirectory.cpp in Sources */,
F54C51D20F1E783200D46E3C /* GUIDialogKaraokeSongSelector.cpp in Sources */,
+ 2F4564D51970129A00396109 /* GUIFontCache.cpp in Sources */,
F54C51D50F1E784800D46E3C /* karaokelyricscdg.cpp in Sources */,
F54C51D80F1E785700D46E3C /* karaokelyrics.cpp in Sources */,
F54C51E50F1E787700D46E3C /* karaokelyricstextkar.cpp in Sources */,
@@ -12731,6 +12739,7 @@
DFF0F45B17528350002DA3A4 /* Control.cpp in Sources */,
DFF0F45C17528350002DA3A4 /* Dialog.cpp in Sources */,
DFF0F45D17528350002DA3A4 /* File.cpp in Sources */,
+ 2F4564D71970129A00396109 /* GUIFontCache.cpp in Sources */,
DFF0F45E17528350002DA3A4 /* InfoTagMusic.cpp in Sources */,
DFF0F45F17528350002DA3A4 /* InfoTagVideo.cpp in Sources */,
DFF0F46017528350002DA3A4 /* Keyboard.cpp in Sources */,
@@ -13529,6 +13538,7 @@
E499131D174E5DAD00741B6D /* GUIVisualisationControl.cpp in Sources */,
E499131E174E5DAD00741B6D /* GUIWindow.cpp in Sources */,
E499131F174E5DAD00741B6D /* GUIWindowManager.cpp in Sources */,
+ 2F4564D61970129A00396109 /* GUIFontCache.cpp in Sources */,
E4991320174E5DAD00741B6D /* GUIWrappingListContainer.cpp in Sources */,
E4991321174E5DAD00741B6D /* imagefactory.cpp in Sources */,
E4991322174E5DAD00741B6D /* IWindowManagerCallback.cpp in Sources */,
diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
index 31167e7d7b..ddadac0734 100644
--- a/project/VS2010Express/XBMC.vcxproj
+++ b/project/VS2010Express/XBMC.vcxproj
@@ -434,6 +434,7 @@
<ClCompile Include="..\..\xbmc\guilib\GUIFadeLabelControl.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFixedListContainer.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFont.cpp" />
+ <ClCompile Include="..\..\xbmc\guilib\GUIFontCache.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFontManager.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFontTTF.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFontTTFDX.cpp" />
@@ -1744,6 +1745,7 @@
<ClInclude Include="..\..\xbmc\guilib\GUIFadeLabelControl.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFixedListContainer.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFont.h" />
+ <ClInclude Include="..\..\xbmc\guilib\GUIFontCache.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFontManager.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFontTTF.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFontTTFDX.h" />
@@ -2541,4 +2543,4 @@
</VisualStudio>
</ProjectExtensions>
<Import Project="$(SolutionDir)\$(ProjectFileName).targets.user" Condition="Exists('$(SolutionDir)\$(ProjectFileName).targets.user')" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
index 9ec497b230..36e35b0d6e 100644
--- a/project/VS2010Express/XBMC.vcxproj.filters
+++ b/project/VS2010Express/XBMC.vcxproj.filters
@@ -988,6 +988,9 @@
<ClCompile Include="..\..\xbmc\guilib\GUIFont.cpp">
<Filter>guilib</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\guilib\GUIFontCache.cpp">
+ <Filter>guilib</Filter>
+ </ClCompile>
<ClCompile Include="..\..\xbmc\guilib\GUIFontManager.cpp">
<Filter>guilib</Filter>
</ClCompile>
@@ -3867,6 +3870,9 @@
<ClInclude Include="..\..\xbmc\guilib\GUIFont.h">
<Filter>guilib</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\guilib\GUIFontCache.h">
+ <Filter>guilib</Filter>
+ </ClInclude>
<ClInclude Include="..\..\xbmc\guilib\GUIFontManager.h">
<Filter>guilib</Filter>
</ClInclude>
@@ -6048,4 +6054,4 @@
<Filter>win32</Filter>
</CustomBuild>
</ItemGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
new file mode 100644
index 0000000000..428f8619a9
--- /dev/null
+++ b/xbmc/guilib/GUIFontCache.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <vector>
+#include "GUIFontTTF.h"
+#include "GraphicContext.h"
+
+template<class Position, class Value>
+void CGUIFontCacheEntry<Position, Value>::Reassign::operator()(CGUIFontCacheEntry<Position, Value> &entry)
+{
+ entry.m_key.m_pos = m_key.m_pos;
+ entry.m_key.m_colors.assign(m_key.m_colors.begin(), m_key.m_colors.end());
+ entry.m_key.m_text.assign(m_key.m_text.begin(), m_key.m_text.end());
+ entry.m_key.m_alignment = m_key.m_alignment;
+ entry.m_key.m_maxPixelWidth = m_key.m_maxPixelWidth;
+ entry.m_key.m_scrolling = m_key.m_scrolling;
+ entry.m_matrix = m_key.m_matrix;
+ entry.m_key.m_scaleX = m_key.m_scaleX;
+ entry.m_key.m_scaleY = m_key.m_scaleY;
+
+ entry.m_lastUsedMillis = m_nowMillis;
+ entry.m_value.clear();
+}
+
+template<class Position, class Value>
+CGUIFontCacheEntry<Position, Value>::~CGUIFontCacheEntry()
+{
+ delete &m_key.m_colors;
+ delete &m_key.m_text;
+ m_value.clear();
+}
+
+template<class Position, class Value>
+Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
+ const vecColors &colors, const vecText &text,
+ uint32_t alignment, float maxPixelWidth,
+ bool scrolling,
+ unsigned int nowMillis, bool &dirtyCache)
+{
+ const CGUIFontCacheKey<Position> key(pos,
+ const_cast<vecColors &>(colors), const_cast<vecText &>(text),
+ alignment, maxPixelWidth,
+ scrolling, g_graphicsContext.GetGUIMatrix(),
+ g_graphicsContext.GetGUIScaleX(), g_graphicsContext.GetGUIScaleY());
+ EntryHashIterator i = m_list.template get<Hash>().find(key);
+ if (i == m_list.template get<Hash>().end())
+ {
+ /* Cache miss */
+ EntryAgeIterator oldest = m_list.template get<Age>().begin();
+ if (!m_list.template get<Age>().empty() && nowMillis - oldest->m_lastUsedMillis > FONT_CACHE_TIME_LIMIT)
+ {
+ /* The oldest existing entry is old enough to expire and reuse */
+ m_list.template get<Hash>().modify(m_list.template project<Hash>(oldest), typename CGUIFontCacheEntry<Position, Value>::Reassign(key, nowMillis));
+ m_list.template get<Age>().relocate(m_list.template get<Age>().end(), oldest);
+ }
+ else
+ {
+ /* We need a new entry instead */
+ /* Yes, this causes the creation an destruction of a temporary entry, but
+ * this code ought to only be used infrequently, when the cache needs to grow */
+ m_list.template get<Age>().push_back(CGUIFontCacheEntry<Position, Value>(*this, key, nowMillis));
+ }
+ dirtyCache = true;
+ return (--m_list.template get<Age>().end())->m_value;
+ }
+ else
+ {
+ /* Cache hit */
+ /* Update time in entry and move to the back of the list */
+ i->m_lastUsedMillis = nowMillis;
+ m_list.template get<Age>().relocate(m_list.template get<Age>().end(), m_list.template project<Age>(i));
+ dirtyCache = false;
+ return i->m_value;
+ }
+}
+
+template<class Position, class Value>
+void CGUIFontCache<Position, Value>::Flush()
+{
+ m_list.template get<Age>().clear();
+}
+
+template void CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Reassign::operator()(CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> &entry);
+template CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::~CGUIFontCacheEntry();
+template CGUIFontCacheStaticValue &CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
+template void CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Flush();
diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
new file mode 100644
index 0000000000..9aea90a46f
--- /dev/null
+++ b/xbmc/guilib/GUIFontCache.h
@@ -0,0 +1,225 @@
+/*!
+\file GUIFontCache.h
+\brief
+*/
+
+#ifndef CGUILIB_GUIFONTCACHE_H
+#define CGUILIB_GUIFONTCACHE_H
+#pragma once
+
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <cstddef>
+#include <cstring>
+#include <stdint.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "boost/multi_index_container.hpp"
+#include "boost/multi_index/sequenced_index.hpp"
+#include "boost/multi_index/hashed_index.hpp"
+#include "boost/multi_index/member.hpp"
+#include "boost/shared_ptr.hpp"
+
+#include "TransformMatrix.h"
+
+using namespace boost::multi_index;
+
+#define FONT_CACHE_TIME_LIMIT (1000)
+
+template<class Position, class Value> class CGUIFontCache;
+class CGUIFontTTFBase;
+
+template<class Position>
+struct CGUIFontCacheKey
+{
+ Position m_pos;
+ vecColors &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,
+ vecColors &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;
+
+ /* These need to be declared as mutable to get round the fact that only
+ * const iterators are available. These fields do not affect comparison or
+ * hash functors, so from the container's point of view, they are mutable. */
+ mutable unsigned int m_lastUsedMillis;
+ mutable Value m_value;
+
+ CGUIFontCacheEntry(const CGUIFontCache<Position, Value> &cache, const CGUIFontCacheKey<Position> &key, unsigned int nowMillis) :
+ m_cache(cache),
+ m_key(key.m_pos,
+ *new vecColors, *new vecText,
+ key.m_alignment, key.m_maxPixelWidth,
+ key.m_scrolling, m_matrix,
+ key.m_scaleX, key.m_scaleY),
+ m_lastUsedMillis(nowMillis)
+ {
+ 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(const CGUIFontCacheEntry &other) :
+ m_cache(other.m_cache),
+ m_key(other.m_key.m_pos,
+ *new vecColors, *new vecText,
+ other.m_key.m_alignment, other.m_key.m_maxPixelWidth,
+ other.m_key.m_scrolling, m_matrix,
+ other.m_key.m_scaleX, other.m_key.m_scaleY),
+ m_lastUsedMillis(other.m_lastUsedMillis),
+ m_value(other.m_value)
+ {
+ m_key.m_colors.assign(other.m_key.m_colors.begin(), other.m_key.m_colors.end());
+ m_key.m_text.assign(other.m_key.m_text.begin(), other.m_key.m_text.end());
+ m_matrix = other.m_key.m_matrix;
+ }
+
+ struct Reassign
+ {
+ Reassign(const CGUIFontCacheKey<Position> &key, unsigned int nowMillis) : m_key(key), m_nowMillis(nowMillis) {}
+ void operator()(CGUIFontCacheEntry &entry);
+ private:
+ const CGUIFontCacheKey<Position> &m_key;
+ unsigned int m_nowMillis;
+ };
+
+ ~CGUIFontCacheEntry();
+};
+
+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 += MatrixHashContribution(key);
+ return hash;
+ }
+};
+
+template<class Position>
+struct CGUIFontCacheKeysMatch
+{
+ bool operator()(const CGUIFontCacheKey<Position> &a, const CGUIFontCacheKey<Position> &b) const
+ {
+ 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;
+ }
+};
+
+template<class Position, class Value>
+class CGUIFontCache
+{
+ /* Empty structs used as tags to identify indexes */
+ struct Age {};
+ struct Hash {};
+
+ typedef multi_index_container<
+ CGUIFontCacheEntry<Position, Value>,
+ indexed_by<
+ sequenced<tag<Age> >,
+ hashed_unique<tag<Hash>, member<CGUIFontCacheEntry<Position, Value>, CGUIFontCacheKey<Position>, &CGUIFontCacheEntry<Position, Value>::m_key>, CGUIFontCacheHash<Position>, CGUIFontCacheKeysMatch<Position> >
+ >
+ > EntryList;
+
+ typedef typename EntryList::template index<Age>::type::iterator EntryAgeIterator;
+ typedef typename EntryList::template index<Hash>::type::iterator EntryHashIterator;
+
+ EntryList m_list;
+
+public:
+ const CGUIFontTTFBase &m_font;
+
+ CGUIFontCache(CGUIFontTTFBase &font) : m_font(font) {}
+ Value &Lookup(Position &pos,
+ const vecColors &colors, const vecText &text,
+ uint32_t alignment, float maxPixelWidth,
+ bool scrolling,
+ unsigned int nowMillis, bool &dirtyCache);
+ void Flush();
+};
+
+struct CGUIFontCacheStaticPosition
+{
+ float m_x;
+ float m_y;
+ CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {}
+};
+
+struct CGUIFontCacheStaticValue : public boost::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];
+}
+
+#endif
diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
index 0dcce1d3fc..b048023973 100644
--- a/xbmc/guilib/GUIFontTTF.cpp
+++ b/xbmc/guilib/GUIFontTTF.cpp
@@ -29,6 +29,8 @@
#include "windowing/WindowingFactory.h"
#include "URL.h"
#include "filesystem/File.h"
+#include "threads/SystemClock.h"
+#include "boost/make_shared.hpp"
#include <math.h>
@@ -153,7 +155,7 @@ private:
XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library
#define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary)
-CGUIFontTTFBase::CGUIFontTTFBase(const std::string& strFileName)
+CGUIFontTTFBase::CGUIFontTTFBase(const std::string& strFileName) : m_staticCache(*this)
{
m_texture = NULL;
m_char = NULL;
@@ -354,108 +356,130 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
{
Begin();
- std::vector<SVertex> &vertices = m_vertex;
-
- // save the origin, which is scaled separately
- m_originX = x;
- m_originY = y;
-
- // Check if we will really need to truncate or justify the text
- if ( alignment & XBFONT_TRUNCATED )
+ uint32_t rawAlignment = alignment;
+ bool dirtyCache;
+ CGUIFontCacheStaticPosition staticPos(x, y);
+ boost::shared_ptr<std::vector<SVertex> > tempVertices = boost::make_shared<std::vector<SVertex> >();
+ boost::shared_ptr<std::vector<SVertex> > &vertices = m_staticCache.Lookup(staticPos,
+ colors, text,
+ alignment, maxPixelWidth,
+ scrolling,
+ XbmcThreads::SystemClockMillis(),
+ dirtyCache);
+ if (dirtyCache)
{
- if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
- alignment &= ~XBFONT_TRUNCATED;
- }
- else if ( alignment & XBFONT_JUSTIFIED )
- {
- if ( maxPixelWidth <= 0.0f )
- alignment &= ~XBFONT_JUSTIFIED;
- }
+ // save the origin, which is scaled separately
+ m_originX = x;
+ m_originY = y;
+
+ // Check if we will really need to truncate or justify the text
+ if ( alignment & XBFONT_TRUNCATED )
+ {
+ if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
+ alignment &= ~XBFONT_TRUNCATED;
+ }
+ else if ( alignment & XBFONT_JUSTIFIED )
+ {
+ if ( maxPixelWidth <= 0.0f )
+ alignment &= ~XBFONT_JUSTIFIED;
+ }
- // calculate sizing information
- float startX = 0;
- float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering
+ // calculate sizing information
+ float startX = 0;
+ float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering
- if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
- {
- // Get the extent of this line
- float w = GetTextWidthInternal( text.begin(), text.end() );
+ if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
+ {
+ // Get the extent of this line
+ float w = GetTextWidthInternal( text.begin(), text.end() );
- if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues
- w = maxPixelWidth;
+ if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues
+ w = maxPixelWidth;
- if ( alignment & XBFONT_CENTER_X)
- w *= 0.5f;
- // Offset this line's starting position
- startX -= w;
- }
+ if ( alignment & XBFONT_CENTER_X)
+ w *= 0.5f;
+ // Offset this line's starting position
+ startX -= w;
+ }
- float spacePerLetter = 0; // for justification effects
- if ( alignment & XBFONT_JUSTIFIED )
- {
- // first compute the size of the text to render in both characters and pixels
- unsigned int lineChars = 0;
- float linePixels = 0;
- for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
+ float spacePerLetter = 0; // for justification effects
+ if ( alignment & XBFONT_JUSTIFIED )
{
- Character *ch = GetCharacter(*pos);
- if (ch)
- { // spaces have multiple times the justification spacing of normal letters
- lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
- linePixels += ch->advance;
+ // first compute the size of the text to render in both characters and pixels
+ unsigned int lineChars = 0;
+ float linePixels = 0;
+ for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
+ {
+ Character *ch = GetCharacter(*pos);
+ if (ch)
+ { // spaces have multiple times the justification spacing of normal letters
+ lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
+ linePixels += ch->advance;
+ }
}
+ if (lineChars > 1)
+ spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
}
- if (lineChars > 1)
- spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
- }
- float cursorX = 0; // current position along the line
-
- for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
- {
- // If starting text on a new line, determine justification effects
- // Get the current letter in the std::string
- color_t color = (*pos & 0xff0000) >> 16;
- if (color >= colors.size())
- color = 0;
- color = colors[color];
-
- // grab the next character
- Character *ch = GetCharacter(*pos);
- if (!ch) continue;
+ float cursorX = 0; // current position along the line
- if ( alignment & XBFONT_TRUNCATED )
+ for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
{
- // Check if we will be exceeded the max allowed width
- if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
- {
- // Yup. Let's draw the ellipses, then bail
- // Perhaps we should really bail to the next line in this case??
- Character *period = GetCharacter(L'.');
- if (!period)
- break;
+ // If starting text on a new line, determine justification effects
+ // Get the current letter in the CStdString
+ color_t color = (*pos & 0xff0000) >> 16;
+ if (color >= colors.size())
+ color = 0;
+ color = colors[color];
+
+ // grab the next character
+ Character *ch = GetCharacter(*pos);
+ if (!ch) continue;
- for (int i = 0; i < 3; i++)
+ if ( alignment & XBFONT_TRUNCATED )
+ {
+ // Check if we will be exceeded the max allowed width
+ if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
{
- RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices);
- cursorX += period->advance;
+ // Yup. Let's draw the ellipses, then bail
+ // Perhaps we should really bail to the next line in this case??
+ Character *period = GetCharacter(L'.');
+ if (!period)
+ break;
+
+ for (int i = 0; i < 3; i++)
+ {
+ RenderCharacter(startX + cursorX, startY, period, color, !scrolling, *tempVertices);
+ cursorX += period->advance;
+ }
+ break;
}
- break;
}
- }
- else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
- break; // exceeded max allowed width - stop rendering
+ else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
+ break; // exceeded max allowed width - stop rendering
- RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices);
- if ( alignment & XBFONT_JUSTIFIED )
- {
- if ((*pos & 0xffff) == L' ')
- cursorX += ch->advance + spacePerLetter * justification_word_weight;
+ RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, *tempVertices);
+ if ( alignment & XBFONT_JUSTIFIED )
+ {
+ if ((*pos & 0xffff) == L' ')
+ cursorX += ch->advance + spacePerLetter * justification_word_weight;
+ else
+ cursorX += ch->advance + spacePerLetter;
+ }
else
- cursorX += ch->advance + spacePerLetter;
+ cursorX += ch->advance;
}
- else
- cursorX += ch->advance;
+ m_staticCache.Lookup(staticPos,
+ colors, text,
+ rawAlignment, maxPixelWidth,
+ scrolling,
+ XbmcThreads::SystemClockMillis(),
+ dirtyCache) = *static_cast<CGUIFontCacheStaticValue *>(&tempVertices);
+ /* Append the new vertices to the set collected since the first Begin() call */
+ m_vertex.insert(m_vertex.end(), tempVertices->begin(), tempVertices->end());
}
+ else
+ /* Append the vertices from the cache to the set collected since the first Begin() call */
+ m_vertex.insert(m_vertex.end(), vertices->begin(), vertices->end());
End();
}
diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
index 2aefcfb961..315f449108 100644
--- a/xbmc/guilib/GUIFontTTF.h
+++ b/xbmc/guilib/GUIFontTTF.h
@@ -70,6 +70,9 @@ struct SVertex
};
+#include "GUIFontCache.h"
+
+
class CGUIFontTTFBase
{
friend class CGUIFont;
@@ -172,6 +175,8 @@ protected:
std::string m_strFileName;
XUTILS::auto_buffer m_fontFileInMemory; // used only in some cases, see CFreeTypeLibrary::GetFont()
+ CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> m_staticCache;
+
private:
virtual bool FirstBegin() = 0;
virtual void LastEnd() = 0;
diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
index f39a24b8ca..5f02eaf2c3 100644
--- a/xbmc/guilib/GUIFontTTFGL.cpp
+++ b/xbmc/guilib/GUIFontTTFGL.cpp
@@ -221,6 +221,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
m_textureScaleX = 1.0f / m_textureWidth;
if (m_textureHeight < newHeight)
CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight);
+ m_staticCache.Flush();
memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
if (m_texture)
diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
index a108fcaf00..b41f443409 100644
--- a/xbmc/guilib/GraphicContext.h
+++ b/xbmc/guilib/GraphicContext.h
@@ -146,6 +146,7 @@ public:
inline void ScaleFinalCoords(float &x, float &y, float &z) const XBMC_FORCE_INLINE { m_finalTransform.matrix.TransformPosition(x, y, z); }
bool RectIsAngled(float x1, float y1, float x2, float y2) const;
+ inline const TransformMatrix &GetGUIMatrix() const XBMC_FORCE_INLINE { return m_finalTransform.matrix; }
inline float GetGUIScaleX() const XBMC_FORCE_INLINE { return m_finalTransform.scaleX; }
inline float GetGUIScaleY() const XBMC_FORCE_INLINE { return m_finalTransform.scaleY; }
inline color_t MergeAlpha(color_t color) const XBMC_FORCE_INLINE
diff --git a/xbmc/guilib/Makefile.in b/xbmc/guilib/Makefile.in
index 68c11f4e06..2b911b3410 100644
--- a/xbmc/guilib/Makefile.in
+++ b/xbmc/guilib/Makefile.in
@@ -23,6 +23,7 @@ SRCS += GUIEditControl.cpp
SRCS += GUIFadeLabelControl.cpp
SRCS += GUIFixedListContainer.cpp
SRCS += GUIFont.cpp
+SRCS += GUIFontCache.cpp
SRCS += GUIFontManager.cpp
SRCS += GUIFontTTF.cpp
SRCS += GUIImage.cpp
diff --git a/xbmc/guilib/TransformMatrix.h b/xbmc/guilib/TransformMatrix.h
index f351c99b81..bb5e8d7355 100644
--- a/xbmc/guilib/TransformMatrix.h
+++ b/xbmc/guilib/TransformMatrix.h
@@ -245,3 +245,14 @@ public:
float alpha;
bool identity;
};
+
+inline bool operator==(const TransformMatrix &a, const TransformMatrix &b)
+{
+ return a.alpha == b.alpha && ((a.identity && b.identity) ||
+ (!a.identity && !b.identity && std::equal(&a.m[0][0], &a.m[0][0] + sizeof (a.m) / sizeof (a.m[0][0]), &b.m[0][0])));
+}
+
+inline bool operator!=(const TransformMatrix &a, const TransformMatrix &b)
+{
+ return !operator==(a, b);
+}