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