1 //========================================================================
2 //
3 // SplashFont.cc
4 //
5 // Copyright 2003-2013 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include <string.h>
16 #include "gmem.h"
17 #include "SplashMath.h"
18 #include "SplashGlyphBitmap.h"
19 #include "SplashFontFile.h"
20 #include "SplashFont.h"
21
22 //------------------------------------------------------------------------
23
24 // font cache size parameters
25 #define splashFontCacheAssoc 8
26 #define splashFontCacheMaxSets 8
27 #define splashFontCacheSize (128*1024)
28
29 //------------------------------------------------------------------------
30
31 struct SplashFontCacheTag {
32 int c;
33 short xFrac, yFrac; // x and y fractions
34 int mru; // valid bit (0x80000000) and MRU index
35 int x, y, w, h; // offset and size of glyph
36 };
37
38 //------------------------------------------------------------------------
39 // SplashFont
40 //------------------------------------------------------------------------
41
SplashFont(SplashFontFile * fontFileA,SplashCoord * matA,SplashCoord * textMatA,GBool aaA)42 SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA,
43 SplashCoord *textMatA, GBool aaA) {
44 fontFile = fontFileA;
45 fontFile->incRefCnt();
46 mat[0] = matA[0];
47 mat[1] = matA[1];
48 mat[2] = matA[2];
49 mat[3] = matA[3];
50 textMat[0] = textMatA[0];
51 textMat[1] = textMatA[1];
52 textMat[2] = textMatA[2];
53 textMat[3] = textMatA[3];
54 aa = aaA;
55
56 cache = NULL;
57 cacheTags = NULL;
58
59 xMin = yMin = xMax = yMax = 0;
60 }
61
initCache()62 void SplashFont::initCache() {
63 int i;
64
65 // this should be (max - min + 1), but we add some padding to
66 // deal with rounding errors
67 glyphW = xMax - xMin + 3;
68 glyphH = yMax - yMin + 3;
69 if (aa) {
70 glyphSize = glyphW * glyphH;
71 } else {
72 glyphSize = ((glyphW + 7) >> 3) * glyphH;
73 }
74
75 // set up the glyph pixmap cache
76 cacheAssoc = splashFontCacheAssoc;
77 for (cacheSets = splashFontCacheMaxSets;
78 cacheSets > 1 &&
79 cacheSets * cacheAssoc * glyphSize > splashFontCacheSize;
80 cacheSets >>= 1) ;
81 cache = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize);
82 cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc,
83 sizeof(SplashFontCacheTag));
84 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
85 cacheTags[i].mru = i & (cacheAssoc - 1);
86 }
87 }
88
~SplashFont()89 SplashFont::~SplashFont() {
90 fontFile->decRefCnt();
91 if (cache) {
92 gfree(cache);
93 }
94 if (cacheTags) {
95 gfree(cacheTags);
96 }
97 }
98
getGlyph(int c,int xFrac,int yFrac,SplashGlyphBitmap * bitmap)99 GBool SplashFont::getGlyph(int c, int xFrac, int yFrac,
100 SplashGlyphBitmap *bitmap) {
101 SplashGlyphBitmap bitmap2;
102 int size;
103 Guchar *p;
104 int i, j, k;
105
106 // no fractional coordinates for large glyphs or non-anti-aliased
107 // glyphs
108 if (!aa || glyphH > 50) {
109 xFrac = yFrac = 0;
110 }
111
112 // check the cache
113 i = (c & (cacheSets - 1)) * cacheAssoc;
114 for (j = 0; j < cacheAssoc; ++j) {
115 if ((cacheTags[i+j].mru & 0x80000000) &&
116 cacheTags[i+j].c == c &&
117 (int)cacheTags[i+j].xFrac == xFrac &&
118 (int)cacheTags[i+j].yFrac == yFrac) {
119 bitmap->x = cacheTags[i+j].x;
120 bitmap->y = cacheTags[i+j].y;
121 bitmap->w = cacheTags[i+j].w;
122 bitmap->h = cacheTags[i+j].h;
123 for (k = 0; k < cacheAssoc; ++k) {
124 if (k != j &&
125 (cacheTags[i+k].mru & 0x7fffffff) <
126 (cacheTags[i+j].mru & 0x7fffffff)) {
127 ++cacheTags[i+k].mru;
128 }
129 }
130 cacheTags[i+j].mru = 0x80000000;
131 bitmap->aa = aa;
132 bitmap->data = cache + (i+j) * glyphSize;
133 bitmap->freeData = gFalse;
134 return gTrue;
135 }
136 }
137
138 // generate the glyph bitmap
139 if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) {
140 return gFalse;
141 }
142
143 // if the glyph doesn't fit in the bounding box, return a temporary
144 // uncached bitmap
145 if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
146 *bitmap = bitmap2;
147 return gTrue;
148 }
149
150 // insert glyph pixmap in cache
151 if (aa) {
152 size = bitmap2.w * bitmap2.h;
153 } else {
154 size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
155 }
156 p = NULL; // make gcc happy
157 for (j = 0; j < cacheAssoc; ++j) {
158 if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) {
159 cacheTags[i+j].mru = 0x80000000;
160 cacheTags[i+j].c = c;
161 cacheTags[i+j].xFrac = (short)xFrac;
162 cacheTags[i+j].yFrac = (short)yFrac;
163 cacheTags[i+j].x = bitmap2.x;
164 cacheTags[i+j].y = bitmap2.y;
165 cacheTags[i+j].w = bitmap2.w;
166 cacheTags[i+j].h = bitmap2.h;
167 p = cache + (i+j) * glyphSize;
168 memcpy(p, bitmap2.data, size);
169 } else {
170 ++cacheTags[i+j].mru;
171 }
172 }
173 *bitmap = bitmap2;
174 bitmap->data = p;
175 bitmap->freeData = gFalse;
176 if (bitmap2.freeData) {
177 gfree(bitmap2.data);
178 }
179 return gTrue;
180 }
181