]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | //======================================================================== |
2 | // | |
3 | // SplashFont.cc | |
4 | // | |
5 | //======================================================================== | |
6 | ||
7 | #include <config.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 | ||
33 | SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, | |
34 | 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 | aa = aaA; | |
42 | ||
43 | cache = NULL; | |
44 | cacheTags = NULL; | |
45 | ||
46 | xMin = yMin = xMax = yMax = 0; | |
47 | } | |
48 | ||
49 | void SplashFont::initCache() { | |
50 | int i; | |
51 | ||
52 | // this should be (max - min + 1), but we add some padding to | |
53 | // deal with rounding errors | |
54 | glyphW = xMax - xMin + 3; | |
55 | glyphH = yMax - yMin + 3; | |
56 | if (aa) { | |
57 | glyphSize = glyphW * glyphH; | |
58 | } else { | |
59 | glyphSize = ((glyphW + 7) >> 3) * glyphH; | |
60 | } | |
61 | ||
62 | // set up the glyph pixmap cache | |
63 | cacheAssoc = 8; | |
64 | if (glyphSize <= 256) { | |
65 | cacheSets = 8; | |
66 | } else if (glyphSize <= 512) { | |
67 | cacheSets = 4; | |
68 | } else if (glyphSize <= 1024) { | |
69 | cacheSets = 2; | |
70 | } else { | |
71 | cacheSets = 1; | |
72 | } | |
73 | cache = (Guchar *)gmallocn(cacheSets* cacheAssoc, glyphSize); | |
74 | cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, | |
75 | sizeof(SplashFontCacheTag)); | |
76 | for (i = 0; i < cacheSets * cacheAssoc; ++i) { | |
77 | cacheTags[i].mru = i & (cacheAssoc - 1); | |
78 | } | |
79 | } | |
80 | ||
81 | SplashFont::~SplashFont() { | |
82 | fontFile->decRefCnt(); | |
83 | if (cache) { | |
84 | gfree(cache); | |
85 | } | |
86 | if (cacheTags) { | |
87 | gfree(cacheTags); | |
88 | } | |
89 | } | |
90 | ||
91 | GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, | |
92 | SplashGlyphBitmap *bitmap) { | |
93 | SplashGlyphBitmap bitmap2; | |
94 | int size; | |
95 | Guchar *p; | |
96 | int i, j, k; | |
97 | ||
98 | // no fractional coordinates for large glyphs or non-anti-aliased | |
99 | // glyphs | |
100 | if (!aa || glyphH > 50) { | |
101 | xFrac = yFrac = 0; | |
102 | } | |
103 | ||
104 | // check the cache | |
105 | i = (c & (cacheSets - 1)) * cacheAssoc; | |
106 | for (j = 0; j < cacheAssoc; ++j) { | |
107 | if ((cacheTags[i+j].mru & 0x80000000) && | |
108 | cacheTags[i+j].c == c && | |
109 | (int)cacheTags[i+j].xFrac == xFrac && | |
110 | (int)cacheTags[i+j].yFrac == yFrac) { | |
111 | bitmap->x = cacheTags[i+j].x; | |
112 | bitmap->y = cacheTags[i+j].y; | |
113 | bitmap->w = cacheTags[i+j].w; | |
114 | bitmap->h = cacheTags[i+j].h; | |
115 | for (k = 0; k < cacheAssoc; ++k) { | |
116 | if (k != j && | |
117 | (cacheTags[i+k].mru & 0x7fffffff) < | |
118 | (cacheTags[i+j].mru & 0x7fffffff)) { | |
119 | ++cacheTags[i+k].mru; | |
120 | } | |
121 | } | |
122 | cacheTags[i+j].mru = 0x80000000; | |
123 | bitmap->aa = aa; | |
124 | bitmap->data = cache + (i+j) * glyphSize; | |
125 | bitmap->freeData = gFalse; | |
126 | return gTrue; | |
127 | } | |
128 | } | |
129 | ||
130 | // generate the glyph bitmap | |
131 | if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) { | |
132 | return gFalse; | |
133 | } | |
134 | ||
135 | // if the glyph doesn't fit in the bounding box, return a temporary | |
136 | // uncached bitmap | |
137 | if (bitmap2.w > glyphW || bitmap2.h > glyphH) { | |
138 | *bitmap = bitmap2; | |
139 | return gTrue; | |
140 | } | |
141 | ||
142 | // insert glyph pixmap in cache | |
143 | if (aa) { | |
144 | size = bitmap2.w * bitmap2.h; | |
145 | } else { | |
146 | size = ((bitmap2.w + 7) >> 3) * bitmap2.h; | |
147 | } | |
148 | p = NULL; // make gcc happy | |
149 | for (j = 0; j < cacheAssoc; ++j) { | |
150 | if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) { | |
151 | cacheTags[i+j].mru = 0x80000000; | |
152 | cacheTags[i+j].c = c; | |
153 | cacheTags[i+j].xFrac = (short)xFrac; | |
154 | cacheTags[i+j].yFrac = (short)yFrac; | |
155 | cacheTags[i+j].x = bitmap2.x; | |
156 | cacheTags[i+j].y = bitmap2.y; | |
157 | cacheTags[i+j].w = bitmap2.w; | |
158 | cacheTags[i+j].h = bitmap2.h; | |
159 | p = cache + (i+j) * glyphSize; | |
160 | memcpy(p, bitmap2.data, size); | |
161 | } else { | |
162 | ++cacheTags[i+j].mru; | |
163 | } | |
164 | } | |
165 | *bitmap = bitmap2; | |
166 | bitmap->data = p; | |
167 | bitmap->freeData = gFalse; | |
168 | if (bitmap2.freeData) { | |
169 | gfree(bitmap2.data); | |
170 | } | |
171 | return gTrue; | |
172 | } |