You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
4.0 KiB
166 lines
4.0 KiB
//======================================================================== |
|
// |
|
// SplashFont.cc |
|
// |
|
//======================================================================== |
|
|
|
#include <aconf.h> |
|
|
|
#ifdef USE_GCC_PRAGMAS |
|
#pragma implementation |
|
#endif |
|
|
|
#include <string.h> |
|
#include "gmem.h" |
|
#include "SplashMath.h" |
|
#include "SplashGlyphBitmap.h" |
|
#include "SplashFontFile.h" |
|
#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 |
|
//------------------------------------------------------------------------ |
|
|
|
SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, |
|
GBool aaA) { |
|
fontFile = fontFileA; |
|
fontFile->incRefCnt(); |
|
mat[0] = matA[0]; |
|
mat[1] = matA[1]; |
|
mat[2] = matA[2]; |
|
mat[3] = matA[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 <= 256) { |
|
cacheSets = 8; |
|
} else if (glyphSize <= 512) { |
|
cacheSets = 4; |
|
} else if (glyphSize <= 1024) { |
|
cacheSets = 2; |
|
} else { |
|
cacheSets = 1; |
|
} |
|
cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize); |
|
cacheTags = (SplashFontCacheTag *)gmalloc(cacheSets * cacheAssoc * |
|
sizeof(SplashFontCacheTag)); |
|
for (i = 0; i < cacheSets * cacheAssoc; ++i) { |
|
cacheTags[i].mru = i & (cacheAssoc - 1); |
|
} |
|
} |
|
|
|
SplashFont::~SplashFont() { |
|
fontFile->decRefCnt(); |
|
if (cache) { |
|
gfree(cache); |
|
} |
|
if (cacheTags) { |
|
gfree(cacheTags); |
|
} |
|
} |
|
|
|
GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, |
|
SplashGlyphBitmap *bitmap) { |
|
SplashGlyphBitmap bitmap2; |
|
int size; |
|
Guchar *p; |
|
int i, j, k; |
|
|
|
// 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; |
|
bitmap->aa = aa; |
|
bitmap->data = cache + (i+j) * glyphSize; |
|
bitmap->freeData = gFalse; |
|
return gTrue; |
|
} |
|
} |
|
|
|
// generate the glyph bitmap |
|
if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) { |
|
return gFalse; |
|
} |
|
|
|
// 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 |
|
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; |
|
} |
|
} |
|
*bitmap = bitmap2; |
|
bitmap->data = p; |
|
bitmap->freeData = gFalse; |
|
if (bitmap2.freeData) { |
|
gfree(bitmap2.data); |
|
} |
|
return gTrue; |
|
}
|
|
|