Coverage Report

Created: 2023-09-25 06:41

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