blob: c98f335cc9b6fe29498141fa35bac256e8a7a060 [file] [log] [blame] [edit]
#ifndef FONTCACHE_H
#define FONTCACHE_H
/**********************************
* Common Preprocessor Directives *
**********************************/
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <unordered_map>
#include <sys/timeb.h>
#include <math.h>
// Set X11 by default, if neither NO_GRAPHICS NOR WIN32 are defined
#ifndef NO_GRAPHICS
#ifndef WIN32
#ifndef X11
#define X11
#endif
#endif // !WIN32
#endif // ~NO_GRAPHICS
#ifdef X11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#endif
#ifdef WIN32
#include <windows.h>
#include <windowsx.h>
#endif
/**
* Maximum sizes for the font cache. The "ZEROS" one is for fonts of zero rotation, and
* the "ROTATED" one is for fonts with other rotation. If you plan on rotating text to
* many rotations, say random ones, and displaying them all at the same time, I suggest
* something large for "ROTATED". The value of "ZEROS" is probably fine.
*
* What these values really mean to you is: because the text drawing is really lazy about
* loading fonts, the "ZEROS" should be at least how many font sizes you expect to be visible
* at a given time, and the "ROTATED" is for how many other different angle-fontsize combinations
* you expect to be visible at a given time. If you program remains within these limits, there
* will be no slow frames, except the first one where you change many visible combinations.
* For after this frame, the font cache has filled up with the fonts that are visible
*
* A quick experiment gave these results:
* 10 fonts => 540 KiB
* 100 fonts => 1.7 MiB
* 1000 fonts => 13.5 Mib
* 10000 fonts => 132.4 Mib
*/
#define FONT_CACHE_SIZE_FOR_ZEROS 40
#define FONT_CACHE_SIZE_FOR_ROTATED 1000
#define NUM_FONT_TYPES 3
#define PI 3.141592654
using namespace std;
#ifdef WIN32
typedef LOGFONT* font_ptr;
#elif defined X11
typedef XftFont* font_ptr;
#else
typedef void* font_ptr;
#endif
/**
* This is a class that caches fonts. It separates out unrotated and rotated fonts,
* for the reason that the unrotated ones are used for bounds estimation anyway, as
* well as that they are generally convenient to have around. For each group, it uses
* a queue to keep track of the order of creation, and when a new font would put a
* cache over capacity, it deletes the oldest one first. The maps are to allow fast
* lookup of fonts from their size and rotation.
*
* This cache is also not very complicated, and it could be, if there were a good reason.
*
* Also note that no references retrieved from this cache should be retained, as
* another part of the program may cause the creation of another font(s) that will
* push yours out. Instead a font should be retrieved every time it is needed.
*
* We're currently using only integer font rotations (in degrees), to avoid having
* a tremendous number of possible font rotations.
*/
class FontCache {
public:
FontCache()
: order_zeros()
, descriptor2font_zeros()
, order_rotated()
, descriptor2font_rotated() {
}
/**
* Retrieve a font from this cache, or create it if it doesn't already exist,
* pushing out, and deleting a font if the new font wont fit in its cache.
* Gets a font from one of two caches depending on whether or not it is rotated.
*/
font_ptr get_font_info(size_t pointsize, int degrees);
/**
* Clear out this cache so that it contains no fonts. This deletes all fonts,
* as well, so make sure any fonts that were retrieved before cannot be referenced.
*/
void clear();
private:
typedef std::pair<size_t, int> font_descriptor;
struct fontdesc_hasher {
inline std::size_t operator()(const font_descriptor& v) const {
std::hash<size_t> sizet_hasher;
std::hash<int> int_hasher;
return sizet_hasher(v.first) ^ int_hasher(v.second);
}
};
FontCache(const FontCache&) = delete;
FontCache& operator=(const FontCache&) = delete;
static void close_font(font_ptr font);
static font_ptr do_font_loading(int pointsize, int degrees);
// this function actually does all the work of get_font_info, but only
// looks/creates in the given map and queue.
template<class queue_type, class map_type>
static font_ptr get_font_info(
size_t pointsize, int degrees,
queue_type& orderqueue, map_type& descr2font_map, size_t max_size);
typedef std::unordered_map<font_descriptor, font_ptr, fontdesc_hasher> font_lookup;
typedef std::deque<font_descriptor> font_queue;
// unrotated fonts (zero rotation)
font_queue order_zeros;
font_lookup descriptor2font_zeros;
// rotated fonts
font_queue order_rotated;
font_lookup descriptor2font_rotated;
};
#endif // FONTCACHE_H