PEBL 2.2
Psychology Experiment Building Language - Cross-platform psychological experiment development system
FontCache.cpp
Go to the documentation of this file.
1#include "FontCache.h"
2#include <iostream>
3
4namespace FontCache {
5
6//
7// FontCacheKey comparison operators
8//
9
10bool FontCacheKey::operator<(const FontCacheKey& other) const {
11 // Compare filename first (most discriminating)
12 if (filename != other.filename) {
13 return filename < other.filename;
14 }
15 // Then style
16 if (style != other.style) {
17 return style < other.style;
18 }
19 // Finally size
20 return size < other.size;
21}
22
23bool FontCacheKey::operator==(const FontCacheKey& other) const {
24 return filename == other.filename &&
25 style == other.style &&
26 size == other.size;
27}
28
29//
30// FontCacheManager singleton access
31//
32
34 static FontCacheManager instance;
35 return instance;
36}
37
38//
39// FontCacheManager::GetFont - Get or create font
40//
41
42TTF_Font* FontCacheManager::GetFont(const FontCacheKey& key, const std::string& full_path) {
43 // Look for font in cache
44 auto it = mCache.find(key);
45
46 if (it != mCache.end()) {
47 // Cache hit - font already loaded, increment ref count
48 it->second.ref_count++;
49 mCacheHits++;
50 return it->second.ttf_font;
51 }
52
53 // Cache miss - need to load font from disk
54 mCacheMisses++;
55
56 // Load font directly using TTF_OpenFont (no RWops/buffer needed)
57 // Modern systems can handle many open file descriptors
58 TTF_Font* new_font = TTF_OpenFont(full_path.c_str(), key.size);
59
60 if (!new_font) {
61 std::cerr << "[FontCache] ERROR: Failed to load font: " << full_path
62 << " - " << TTF_GetError() << std::endl;
63 return nullptr;
64 }
65
66 // Set font style (bold, italic, etc.)
67 TTF_SetFontStyle(new_font, key.style);
68
69 // Add to cache with ref count = 1
70 mCache.insert(std::make_pair(key, CachedTTFFont(new_font)));
71
72 return new_font;
73}
74
75//
76// FontCacheManager::ReleaseFont - Release font reference
77//
78
80 auto it = mCache.find(key);
81
82 if (it == mCache.end()) {
83 // This shouldn't happen if PlatformFont is correctly managing keys
84 std::cerr << "[FontCache] WARNING: Attempted to release non-cached font: "
85 << key.filename << " (style=" << key.style << ", size=" << key.size << ")"
86 << std::endl;
87 return;
88 }
89
90 // Decrement ref count
91 it->second.ref_count--;
92
93 #ifdef FONT_CACHE_DEBUG
94 std::cout << "[FontCache] RELEASE: " << key.filename
95 << " (style=" << key.style << ", size=" << key.size << ")"
96 << " refs=" << it->second.ref_count << std::endl;
97 #endif
98
99 // If no more references, close font and remove from cache
100 if (it->second.ref_count <= 0) {
101 if (it->second.ttf_font) {
102 TTF_CloseFont(it->second.ttf_font);
103 }
104
105 #ifdef FONT_CACHE_DEBUG
106 std::cout << "[FontCache] DELETED: " << key.filename
107 << " (style=" << key.style << ", size=" << key.size << ")"
108 << " cache_size=" << (mCache.size() - 1) << std::endl;
109 #endif
110
111 mCache.erase(it);
112 }
113}
114
115//
116// FontCacheManager::GetStats - Get cache statistics
117//
118
119void FontCacheManager::GetStats(int& unique_fonts, int& total_refs,
120 int& cache_hits, int& cache_misses) {
121 unique_fonts = mCache.size();
122 total_refs = 0;
123
124 // Sum up all reference counts
125 for (const auto& pair : mCache) {
126 total_refs += pair.second.ref_count;
127 }
128
129 cache_hits = mCacheHits;
130 cache_misses = mCacheMisses;
131}
132
133//
134// FontCacheManager::PrintCache - Print cache contents for debugging
135//
136
138 std::cout << "\n=== Font Cache Contents ===" << std::endl;
139 std::cout << "Unique fonts in cache: " << mCache.size() << std::endl;
140 std::cout << "Total cache hits: " << mCacheHits << std::endl;
141 std::cout << "Total cache misses: " << mCacheMisses << std::endl;
142
143 if (mCache.empty()) {
144 std::cout << "(cache is empty)" << std::endl;
145 } else {
146 std::cout << "\nCached fonts:" << std::endl;
147 for (const auto& pair : mCache) {
148 std::cout << " " << pair.first.filename
149 << " (style=" << pair.first.style
150 << ", size=" << pair.first.size
151 << ") refs=" << pair.second.ref_count << std::endl;
152 }
153 }
154 std::cout << "==========================\n" << std::endl;
155}
156
157//
158// FontCacheManager destructor - Clean up any remaining fonts
159//
160
161FontCacheManager::~FontCacheManager() {
162 #ifdef FONT_CACHE_DEBUG
163 if (!mCache.empty()) {
164 std::cout << "[FontCache] Destructor: Cleaning up " << mCache.size()
165 << " remaining fonts" << std::endl;
166 }
167 #endif
168
169 // Close all remaining fonts
170 for (auto& pair : mCache) {
171 if (pair.second.ttf_font) {
172 TTF_CloseFont(pair.second.ttf_font);
173 }
174
175 #ifdef FONT_CACHE_DEBUG
176 std::cout << "[FontCache] Destructor: Closed " << pair.first.filename
177 << " (refs=" << pair.second.ref_count << ")" << std::endl;
178 #endif
179 }
180
181 mCache.clear();
182}
183
184} // namespace FontCache
static FontCacheManager & GetInstance()
Get singleton instance.
Definition FontCache.cpp:33
void ReleaseFont(const FontCacheKey &key)
Definition FontCache.cpp:79
TTF_Font * GetFont(const FontCacheKey &key, const std::string &full_path)
Definition FontCache.cpp:42
void PrintCache()
Print cache contents to stdout (for debugging)
void GetStats(int &unique_fonts, int &total_refs, int &cache_hits, int &cache_misses)
bool operator<(const FontCacheKey &other) const
Comparison operator for std::map ordering.
Definition FontCache.cpp:10
bool operator==(const FontCacheKey &other) const
Equality operator for debugging/testing.
Definition FontCache.cpp:23