diff options
author | Ben Avison <bavison@riscosopen.org> | 2014-01-15 17:18:38 +0000 |
---|---|---|
committer | Ben Avison <bavison@riscosopen.org> | 2015-01-26 14:19:52 +0000 |
commit | c8a899ae026c4ac35340100163c98697cbd39931 (patch) | |
tree | a4860ac8c0e7e4f37cb23f79806a6b91e9bfaa44 | |
parent | 3b29905cc65241cdcc6f3a738a9f6517504b4646 (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.pbxproj | 10 | ||||
-rw-r--r-- | project/VS2010Express/XBMC.vcxproj | 4 | ||||
-rw-r--r-- | project/VS2010Express/XBMC.vcxproj.filters | 8 | ||||
-rw-r--r-- | xbmc/guilib/GUIFontCache.cpp | 104 | ||||
-rw-r--r-- | xbmc/guilib/GUIFontCache.h | 225 | ||||
-rw-r--r-- | xbmc/guilib/GUIFontTTF.cpp | 192 | ||||
-rw-r--r-- | xbmc/guilib/GUIFontTTF.h | 5 | ||||
-rw-r--r-- | xbmc/guilib/GUIFontTTFGL.cpp | 1 | ||||
-rw-r--r-- | xbmc/guilib/GraphicContext.h | 1 | ||||
-rw-r--r-- | xbmc/guilib/Makefile.in | 1 | ||||
-rw-r--r-- | xbmc/guilib/TransformMatrix.h | 11 |
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); +} |