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