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