* Optimise FTFace::KernAdvance() so that kerning for font indices < 128 is precomputed during FTFace() instantiation to avoid calling FT_Get_Kerning() too often. Patch by Sean Morrison, taken from bzflag commit r14652, reworked for safety and performance by me.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
diff --git a/src/FTCharmap.cpp b/src/FTCharmap.cpp
index c4cd1b8..545a0c8 100644
--- a/src/FTCharmap.cpp
+++ b/src/FTCharmap.cpp
@@ -40,7 +40,7 @@ FTCharmap::FTCharmap(FTFace* face)
ftEncoding = ftFace->charmap->encoding;
- for(int i = 0; i < FTCharmap::MAX_PRECOMPUTED; i++)
+ for(unsigned int i = 0; i < FTCharmap::MAX_PRECOMPUTED; i++)
{
charIndexCache[i] = FT_Get_Char_Index(ftFace, i);
}
diff --git a/src/FTCharmap.h b/src/FTCharmap.h
index 5b48213..354c494 100644
--- a/src/FTCharmap.h
+++ b/src/FTCharmap.h
@@ -152,8 +152,8 @@ class FTCharmap
/**
* Precomputed font indices.
*/
- static const int MAX_PRECOMPUTED = 128;
- unsigned int characterCodeIndices[MAX_PRECOMPUTED];
+ static const unsigned int MAX_PRECOMPUTED = 128;
+ unsigned int charIndexCache[MAX_PRECOMPUTED];
/**
* Current error code.
diff --git a/src/FTFace.cpp b/src/FTFace.cpp
index b2a2c13..a87194f 100644
--- a/src/FTFace.cpp
+++ b/src/FTFace.cpp
@@ -30,9 +30,11 @@
#include FT_TRUETYPE_TABLES_H
-FTFace::FTFace(const char* fontFilePath)
-: numGlyphs(0),
+FTFace::FTFace(const char* fontFilePath, bool precomputeKerning)
+: ftFace(0),
+ numGlyphs(0),
fontEncodingList(0),
+ kerningCache(0),
err(0)
{
const FT_Long DEFAULT_FACE_INDEX = 0;
@@ -40,21 +42,25 @@ FTFace::FTFace(const char* fontFilePath)
err = FT_New_Face(*FTLibrary::Instance().GetLibrary(), fontFilePath,
DEFAULT_FACE_INDEX, ftFace);
-
if(err)
{
delete ftFace;
ftFace = 0;
+ return;
}
- else
+
+ numGlyphs = (*ftFace)->num_glyphs;
+ hasKerningTable = FT_HAS_KERNING((*ftFace));
+
+ if(hasKerningTable && precomputeKerning)
{
- numGlyphs = (*ftFace)->num_glyphs;
- hasKerningTable = FT_HAS_KERNING((*ftFace));
+ BuildKerningCache();
}
}
-FTFace::FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes)
+FTFace::FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes,
+ bool precomputeKerning)
: numGlyphs(0),
err(0)
{
@@ -68,16 +74,26 @@ FTFace::FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes)
{
delete ftFace;
ftFace = 0;
+ return;
}
- else
+
+ numGlyphs = (*ftFace)->num_glyphs;
+ hasKerningTable = FT_HAS_KERNING((*ftFace));
+
+ if(hasKerningTable && precomputeKerning)
{
- numGlyphs = (*ftFace)->num_glyphs;
+ BuildKerningCache();
}
}
FTFace::~FTFace()
{
+ if(kerningCache)
+ {
+ delete[] kerningCache;
+ }
+
if(ftFace)
{
FT_Done_Face(*ftFace);
@@ -141,23 +157,34 @@ FT_Encoding* FTFace::CharMapList()
FTPoint FTFace::KernAdvance(unsigned int index1, unsigned int index2)
{
float x, y;
- x = y = 0.0f;
- if(hasKerningTable && index1 && index2)
+ if(!hasKerningTable || !index1 || !index2)
{
- FT_Vector kernAdvance;
- kernAdvance.x = kernAdvance.y = 0;
+ return FTPoint(0.0f, 0.0f);
+ }
- err = FT_Get_Kerning(*ftFace, index1, index2, ft_kerning_unfitted,
- &kernAdvance);
- if(!err)
- {
- x = static_cast<float>(kernAdvance.x) / 64.0f;
- y = static_cast<float>(kernAdvance.y) / 64.0f;
- }
+ if(kerningCache && index1 < FTFace::MAX_PRECOMPUTED
+ && index2 < FTFace::MAX_PRECOMPUTED)
+ {
+ x = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1)];
+ y = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1) + 1];
+ return FTPoint(x, y);
}
- return FTPoint(x, y, 0.0);
+ FT_Vector kernAdvance;
+ kernAdvance.x = kernAdvance.y = 0;
+
+ err = FT_Get_Kerning(*ftFace, index1, index2, ft_kerning_unfitted,
+ &kernAdvance);
+ if(err)
+ {
+ return FTPoint(0.0f, 0.0f);
+ }
+
+ x = static_cast<float>(kernAdvance.x) / 64.0f;
+ y = static_cast<float>(kernAdvance.y) / 64.0f;
+
+ return FTPoint(x, y);
}
@@ -172,3 +199,32 @@ FT_GlyphSlot FTFace::Glyph(unsigned int index, FT_Int load_flags)
return (*ftFace)->glyph;
}
+
+void FTFace::BuildKerningCache()
+{
+ FT_Vector kernAdvance;
+ kernAdvance.x = 0;
+ kernAdvance.y = 0;
+ kerningCache = new float[FTFace::MAX_PRECOMPUTED
+ * FTFace::MAX_PRECOMPUTED * 2];
+ for(unsigned int j = 0; j < FTFace::MAX_PRECOMPUTED; j++)
+ {
+ for(unsigned int i = 0; i < FTFace::MAX_PRECOMPUTED; i++)
+ {
+ err = FT_Get_Kerning(*ftFace, i, j, ft_kerning_unfitted,
+ &kernAdvance);
+ if(err)
+ {
+ delete[] kerningCache;
+ kerningCache = NULL;
+ return;
+ }
+
+ kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i)] =
+ static_cast<float>(kernAdvance.x) / 64.0f;
+ kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i) + 1] =
+ static_cast<float>(kernAdvance.y) / 64.0f;
+ }
+ }
+}
+
diff --git a/src/FTFace.h b/src/FTFace.h
index 36e02c6..899822f 100644
--- a/src/FTFace.h
+++ b/src/FTFace.h
@@ -48,7 +48,7 @@ class FTFace
*
* @param fontFilePath font file path.
*/
- FTFace(const char* fontFilePath);
+ FTFace(const char* fontFilePath, bool precomputeKerning = true);
/**
* Read face data from an in-memory buffer. Error is set.
@@ -56,7 +56,8 @@ class FTFace
* @param pBufferBytes the in-memory buffer
* @param bufferSizeInBytes the length of the buffer in bytes
*/
- FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes);
+ FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes,
+ bool precomputeKerning = true);
/**
* Destructor
@@ -161,7 +162,14 @@ class FTFace
/**
* This face has kerning tables
*/
- bool hasKerningTable;
+ bool hasKerningTable;
+
+ /**
+ * If this face has kerning tables, we can cache them.
+ */
+ void BuildKerningCache();
+ static const unsigned int MAX_PRECOMPUTED = 128;
+ float *kerningCache;
/**
* Current error code. Zero means no error.