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