[poppler] change font cache policy to improve performance.
Sam Liao
phyomh at gmail.com
Sat Aug 27 22:26:13 PDT 2011
Most of the efforts of font rendering is wasted on makeGlyph as
for the cache mechinism, this fix tries to use a unlimited cache
to improve the performance. Testing result of the perf-test program
showes up it reduces about more than 25% running time.
Possible further improvement not added:
- SplashFontEngine cache size/mechanism. This is also a fixed-size
cache.
---
splash/SplashFTFont.cc | 65 -------------------
splash/SplashFTFontFile.cc | 1 -
splash/SplashFont.cc | 153 +++++++++----------------------------------
splash/SplashFont.h | 46 ++++++++-----
splash/SplashT1FontFile.cc | 1 -
5 files changed, 61 insertions(+), 205 deletions(-)
diff --git a/splash/SplashFTFont.cc b/splash/SplashFTFont.cc
index eea3d64..d8edb18 100644
--- a/splash/SplashFTFont.cc
+++ b/splash/SplashFTFont.cc
@@ -62,8 +62,6 @@ SplashFTFont::SplashFTFont(SplashFTFontFile
*fontFileA, SplashCoord *matA,
enableSlightHinting(fontFileA->engine->enableSlightHinting)
{
FT_Face face;
- double div;
- int x, y;
face = fontFileA->face;
if (FT_New_Size(face, &sizeObj)) {
@@ -81,69 +79,6 @@ SplashFTFont::SplashFTFont(SplashFTFontFile
*fontFileA, SplashCoord *matA,
// arithmetic doesn't work so well
textScale = splashSqrt(textMat[2]*textMat[2] + textMat[3]*textMat[3]) / size;
- div = face->bbox.xMax > 20000 ? 65536 : 1;
-
- // transform the four corners of the font bounding box -- the min
- // and max values form the bounding box of the transformed font
- x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) /
- (div * face->units_per_EM));
- xMin = xMax = x;
- y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) /
- (div * face->units_per_EM));
- yMin = yMax = y;
- x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) /
- (div * face->units_per_EM));
- if (x < xMin) {
- xMin = x;
- } else if (x > xMax) {
- xMax = x;
- }
- y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) /
- (div * face->units_per_EM));
- if (y < yMin) {
- yMin = y;
- } else if (y > yMax) {
- yMax = y;
- }
- x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) /
- (div * face->units_per_EM));
- if (x < xMin) {
- xMin = x;
- } else if (x > xMax) {
- xMax = x;
- }
- y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) /
- (div * face->units_per_EM));
- if (y < yMin) {
- yMin = y;
- } else if (y > yMax) {
- yMax = y;
- }
- x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) /
- (div * face->units_per_EM));
- if (x < xMin) {
- xMin = x;
- } else if (x > xMax) {
- xMax = x;
- }
- y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) /
- (div * face->units_per_EM));
- if (y < yMin) {
- yMin = y;
- } else if (y > yMax) {
- yMax = y;
- }
- // This is a kludge: some buggy PDF generators embed fonts with
- // zero bounding boxes.
- if (xMax == xMin) {
- xMin = 0;
- xMax = (int)size;
- }
- if (yMax == yMin) {
- yMin = 0;
- yMax = (int)((SplashCoord)1.2 * size);
- }
-
// compute the transform matrix
#if USE_FIXEDPOINT
matrix.xx = (FT_Fixed)((mat[0] / size).getRaw());
diff --git a/splash/SplashFTFontFile.cc b/splash/SplashFTFontFile.cc
index 160481e..40aac17 100644
--- a/splash/SplashFTFontFile.cc
+++ b/splash/SplashFTFontFile.cc
@@ -132,7 +132,6 @@ SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat,
SplashFont *font;
font = new SplashFTFont(this, mat, textMat);
- font->initCache();
return font;
}
diff --git a/splash/SplashFont.cc b/splash/SplashFont.cc
index 2bfcdc8..58ae214 100644
--- a/splash/SplashFont.cc
+++ b/splash/SplashFont.cc
@@ -32,15 +32,6 @@
#include "SplashFont.h"
//------------------------------------------------------------------------
-
-struct SplashFontCacheTag {
- int c;
- short xFrac, yFrac; // x and y fractions
- int mru; // valid bit (0x80000000) and MRU index
- int x, y, w, h; // offset and size of glyph
-};
-
-//------------------------------------------------------------------------
// SplashFont
//------------------------------------------------------------------------
@@ -57,106 +48,45 @@ SplashFont::SplashFont(SplashFontFile *fontFileA,
SplashCoord *matA,
textMat[2] = textMatA[2];
textMat[3] = textMatA[3];
aa = aaA;
-
- cache = NULL;
- cacheTags = NULL;
-
- xMin = yMin = xMax = yMax = 0;
-}
-
-void SplashFont::initCache() {
- int i;
-
- // this should be (max - min + 1), but we add some padding to
- // deal with rounding errors
- glyphW = xMax - xMin + 3;
- glyphH = yMax - yMin + 3;
- if (aa) {
- glyphSize = glyphW * glyphH;
- } else {
- glyphSize = ((glyphW + 7) >> 3) * glyphH;
- }
-
- // set up the glyph pixmap cache
- cacheAssoc = 8;
- if (glyphSize <= 64) {
- cacheSets = 32;
- } else if (glyphSize <= 128) {
- cacheSets = 16;
- } else if (glyphSize <= 256) {
- cacheSets = 8;
- } else if (glyphSize <= 512) {
- cacheSets = 4;
- } else if (glyphSize <= 1024) {
- cacheSets = 2;
- } else {
- cacheSets = 1;
- }
- cache = (Guchar *)gmallocn_checkoverflow(cacheSets* cacheAssoc, glyphSize);
- if (cache != NULL) {
- cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc,
- sizeof(SplashFontCacheTag));
- for (i = 0; i < cacheSets * cacheAssoc; ++i) {
- cacheTags[i].mru = i & (cacheAssoc - 1);
- }
- } else {
- cacheAssoc = 0;
- }
}
SplashFont::~SplashFont() {
fontFile->decRefCnt();
- if (cache) {
- gfree(cache);
- }
- if (cacheTags) {
- gfree(cacheTags);
- }
}
GBool SplashFont::getGlyph(int c, int xFrac, int yFrac,
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip,
SplashClipResult *clipRes) {
SplashGlyphBitmap bitmap2;
int size;
- Guchar *p;
- int i, j, k;
+ SplashFontCacheKey key;
+ SplashFontCacheEntity ent;
// no fractional coordinates for large glyphs or non-anti-aliased
// glyphs
- if (!aa || glyphH > 50) {
+ if (!aa) {
xFrac = yFrac = 0;
}
- // check the cache
- i = (c & (cacheSets - 1)) * cacheAssoc;
- for (j = 0; j < cacheAssoc; ++j) {
- if ((cacheTags[i+j].mru & 0x80000000) &&
- cacheTags[i+j].c == c &&
- (int)cacheTags[i+j].xFrac == xFrac &&
- (int)cacheTags[i+j].yFrac == yFrac) {
- bitmap->x = cacheTags[i+j].x;
- bitmap->y = cacheTags[i+j].y;
- bitmap->w = cacheTags[i+j].w;
- bitmap->h = cacheTags[i+j].h;
- for (k = 0; k < cacheAssoc; ++k) {
- if (k != j &&
- (cacheTags[i+k].mru & 0x7fffffff) <
- (cacheTags[i+j].mru & 0x7fffffff)) {
- ++cacheTags[i+k].mru;
- }
- }
- cacheTags[i+j].mru = 0x80000000;
+ key.c = c;
+ key.xFrac = (short) xFrac;
+ key.yFrac = (short) yFrac;
+
+ SplashFontCache::iterator iter = cache.find(key);
+
+ if (iter != cache.end()) {
+ bitmap->x = iter->second.x;
+ bitmap->y = iter->second.y;
+ bitmap->w = iter->second.w;
+ bitmap->h = iter->second.h;
bitmap->aa = aa;
- bitmap->data = cache + (i+j) * glyphSize;
+ bitmap->data = iter->second.data.get();
bitmap->freeData = gFalse;
*clipRes = clip->testRect(x0 - bitmap->x,
y0 - bitmap->y,
x0 - bitmap->x + bitmap->w - 1,
y0 - bitmap->y + bitmap->h - 1);
-
return gTrue;
- }
}
// generate the glyph bitmap
@@ -171,49 +101,30 @@ GBool SplashFont::getGlyph(int c, int xFrac, int yFrac,
return gTrue;
}
- // if the glyph doesn't fit in the bounding box, return a temporary
- // uncached bitmap
- if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
- *bitmap = bitmap2;
- return gTrue;
- }
-
// insert glyph pixmap in cache
if (aa) {
size = bitmap2.w * bitmap2.h;
} else {
size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
}
- p = NULL; // make gcc happy
- if (cacheAssoc == 0)
- {
- // we had problems on the malloc of the cache, so ignore it
- *bitmap = bitmap2;
- }
- else
- {
- for (j = 0; j < cacheAssoc; ++j) {
- if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) {
- cacheTags[i+j].mru = 0x80000000;
- cacheTags[i+j].c = c;
- cacheTags[i+j].xFrac = (short)xFrac;
- cacheTags[i+j].yFrac = (short)yFrac;
- cacheTags[i+j].x = bitmap2.x;
- cacheTags[i+j].y = bitmap2.y;
- cacheTags[i+j].w = bitmap2.w;
- cacheTags[i+j].h = bitmap2.h;
- p = cache + (i+j) * glyphSize;
- memcpy(p, bitmap2.data, size);
- } else {
- ++cacheTags[i+j].mru;
+
+ ent.x = bitmap2.x;
+ ent.y = bitmap2.y;
+ ent.w = bitmap2.w;
+ ent.h = bitmap2.h;
+ ent.data = GucharPtr((Guchar *)gmallocn_checkoverflow (1, size), gfree);
+ if (ent.data.get() != NULL) {
+ memcpy(ent.data.get(), bitmap2.data, size);
+ cache[key] = ent;
+
+ *bitmap = bitmap2;
+ bitmap->data = ent.data.get();
+ bitmap->freeData = gFalse;
+ if (bitmap2.freeData) {
+ gfree(bitmap2.data);
}
- }
- *bitmap = bitmap2;
- bitmap->data = p;
- bitmap->freeData = gFalse;
- if (bitmap2.freeData) {
- gfree(bitmap2.data);
- }
+ } else {
+ *bitmap = bitmap2;
}
return gTrue;
}
diff --git a/splash/SplashFont.h b/splash/SplashFont.h
index 78b00d2..1f78dbc 100644
--- a/splash/SplashFont.h
+++ b/splash/SplashFont.h
@@ -26,11 +26,13 @@
#endif
#include "goo/gtypes.h"
+#include "goo/GooString.h"
#include "SplashTypes.h"
#include "SplashClip.h"
+#include <tr1/memory>
+#include <map>
struct SplashGlyphBitmap;
-struct SplashFontCacheTag;
class SplashFontFile;
class SplashPath;
@@ -44,6 +46,31 @@ class SplashPath;
((SplashCoord)1 / (SplashCoord)splashFontFraction)
//------------------------------------------------------------------------
+
+struct SplashFontCacheKey {
+ int c;
+ short xFrac, yFrac; // x and y fractions
+
+ bool operator <(const SplashFontCacheKey& b) const {
+ if (c != b.c)
+ return c < b.c;
+ if (xFrac != b.xFrac)
+ return xFrac < b.xFrac;
+ if (yFrac != b.yFrac)
+ return yFrac < b.yFrac;
+ return false;
+ }
+};
+
+typedef std::tr1::shared_ptr<Guchar> GucharPtr;
+struct SplashFontCacheEntity {
+ int x, y, w, h; // offset and size of glyph
+ GucharPtr data;
+};
+
+typedef std::map<struct SplashFontCacheKey, struct
SplashFontCacheEntity> SplashFontCache;
+
+//------------------------------------------------------------------------
// SplashFont
//------------------------------------------------------------------------
@@ -53,10 +80,6 @@ public:
SplashFont(SplashFontFile *fontFileA, SplashCoord *matA,
SplashCoord *textMatA, GBool aaA);
- // This must be called after the constructor, so that the subclass
- // constructor has a chance to compute the bbox.
- void initCache();
-
virtual ~SplashFont();
SplashFontFile *getFontFile() { return fontFile; }
@@ -96,10 +119,6 @@ public:
// Return the font transform matrix.
SplashCoord *getMatrix() { return mat; }
- // Return the glyph bounding box.
- void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA)
- { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
-
protected:
SplashFontFile *fontFile;
@@ -108,14 +127,7 @@ protected:
SplashCoord textMat[4]; // text transform matrix
// (text space -> user space)
GBool aa; // anti-aliasing
- int xMin, yMin, xMax, yMax; // glyph bounding box
- Guchar *cache; // glyph bitmap cache
- SplashFontCacheTag * // cache tags
- cacheTags;
- int glyphW, glyphH; // size of glyph bitmaps
- int glyphSize; // size of glyph bitmaps, in bytes
- int cacheSets; // number of sets in cache
- int cacheAssoc; // cache associativity (glyphs per set)
+ SplashFontCache cache;
};
#endif
diff --git a/splash/SplashT1FontFile.cc b/splash/SplashT1FontFile.cc
index 3f46ba6..45059a1 100644
--- a/splash/SplashT1FontFile.cc
+++ b/splash/SplashT1FontFile.cc
@@ -127,7 +127,6 @@ SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat,
SplashFont *font;
font = new SplashT1Font(this, mat, textMat);
- font->initCache();
return font;
}
--
1.7.4.1
More information about the poppler
mailing list