]> www.fi.muni.cz Git - evince.git/blob - pdf/splash/SplashFont.cc
My 2005-01-05 change didn't actually fix the problem. Now I just
[evince.git] / pdf / splash / SplashFont.cc
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
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 *)gmalloc(cacheSets * cacheAssoc * glyphSize);
74   cacheTags = (SplashFontCacheTag *)gmalloc(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   // check the cache
99   i = (c & (cacheSets - 1)) * cacheAssoc;
100   for (j = 0; j < cacheAssoc; ++j) {
101     if ((cacheTags[i+j].mru & 0x80000000) &&
102         cacheTags[i+j].c == c &&
103         (int)cacheTags[i+j].xFrac == xFrac &&
104         (int)cacheTags[i+j].yFrac == yFrac) {
105       bitmap->x = cacheTags[i+j].x;
106       bitmap->y = cacheTags[i+j].y;
107       bitmap->w = cacheTags[i+j].w;
108       bitmap->h = cacheTags[i+j].h;
109       for (k = 0; k < cacheAssoc; ++k) {
110         if (k != j &&
111             (cacheTags[i+k].mru & 0x7fffffff) <
112               (cacheTags[i+j].mru & 0x7fffffff)) {
113           ++cacheTags[i+k].mru;
114         }
115       }
116       cacheTags[i+j].mru = 0x80000000;
117       bitmap->aa = aa;
118       bitmap->data = cache + (i+j) * glyphSize;
119       bitmap->freeData = gFalse;
120       return gTrue;
121     }
122   }
123
124   // generate the glyph bitmap
125   if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) {
126     return gFalse;
127   }
128
129   // if the glyph doesn't fit in the bounding box, return a temporary
130   // uncached bitmap
131   if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
132     *bitmap = bitmap2;
133     return gTrue;
134   }
135
136   // insert glyph pixmap in cache
137   if (aa) {
138     size = bitmap2.w * bitmap2.h;
139   } else {
140     size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
141   }
142   p = NULL; // make gcc happy
143   for (j = 0; j < cacheAssoc; ++j) {
144     if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) {
145       cacheTags[i+j].mru = 0x80000000;
146       cacheTags[i+j].c = c;
147       cacheTags[i+j].xFrac = (short)xFrac;
148       cacheTags[i+j].yFrac = (short)yFrac;
149       cacheTags[i+j].x = bitmap2.x;
150       cacheTags[i+j].y = bitmap2.y;
151       cacheTags[i+j].w = bitmap2.w;
152       cacheTags[i+j].h = bitmap2.h;
153       p = cache + (i+j) * glyphSize;
154       memcpy(p, bitmap2.data, size);
155     } else {
156       ++cacheTags[i+j].mru;
157     }
158   }
159   *bitmap = bitmap2;
160   bitmap->data = p;
161   bitmap->freeData = gFalse;
162   if (bitmap2.freeData) {
163     gfree(bitmap2.data);
164   }
165   return gTrue;
166 }