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