Coverage Report

Created: 2026-04-04 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xpdf-4.06/splash/SplashFont.cc
Line
Count
Source
1
//========================================================================
2
//
3
// SplashFont.cc
4
//
5
// Copyright 2003-2013 Glyph & Cog, LLC
6
//
7
//========================================================================
8
9
#include <aconf.h>
10
11
#include <string.h>
12
#include "gmem.h"
13
#include "gmempp.h"
14
#include "SplashMath.h"
15
#include "SplashGlyphBitmap.h"
16
#include "SplashFontFile.h"
17
#include "SplashFont.h"
18
19
//------------------------------------------------------------------------
20
21
// font cache size parameters
22
8.27k
#define splashFontCacheAssoc   8
23
8.27k
#define splashFontCacheMaxSets 8
24
8.27k
#define splashFontCacheSize    (128*1024)
25
26
//------------------------------------------------------------------------
27
28
struct SplashFontCacheTag {
29
  Guint c;
30
  short xFrac, yFrac;   // x and y fractions
31
  int mru;      // valid bit (0x80000000) and MRU index
32
  int x, y, w, h;   // offset and size of glyph
33
};
34
35
//------------------------------------------------------------------------
36
// SplashFont
37
//------------------------------------------------------------------------
38
39
SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA,
40
8.27k
           SplashCoord *textMatA, GBool aaA) {
41
8.27k
  fontFile = fontFileA;
42
8.27k
  fontFile->incRefCnt();
43
8.27k
  mat[0] = matA[0];
44
8.27k
  mat[1] = matA[1];
45
8.27k
  mat[2] = matA[2];
46
8.27k
  mat[3] = matA[3];
47
8.27k
  textMat[0] = textMatA[0];
48
8.27k
  textMat[1] = textMatA[1];
49
8.27k
  textMat[2] = textMatA[2];
50
8.27k
  textMat[3] = textMatA[3];
51
8.27k
  aa = aaA;
52
53
8.27k
  cache = NULL;
54
8.27k
  cacheTags = NULL;
55
56
8.27k
  xMin = yMin = xMax = yMax = 0;
57
8.27k
}
58
59
8.27k
void SplashFont::initCache() {
60
8.27k
  int i;
61
62
  // this should be (max - min + 1), but we add some padding to
63
  // deal with rounding errors
64
8.27k
  glyphW = xMax - xMin + 3;
65
8.27k
  glyphH = yMax - yMin + 3;
66
8.27k
  if (glyphW > 1000 || glyphH > 1000) {
67
    // if the glyphs are too large, don't cache them -- setting the
68
    // cache bitmap size to something tiny will cause getGlyph() to
69
    // fall back to the uncached case
70
0
    glyphW = glyphH = 0;
71
0
    glyphSize = 0;
72
0
    cacheSets = 0;
73
0
    cacheAssoc = 0;
74
0
    return;
75
0
  }
76
8.27k
  if (aa) {
77
8.27k
    glyphSize = glyphW * glyphH;
78
8.27k
  } else {
79
0
    glyphSize = ((glyphW + 7) >> 3) * glyphH;
80
0
  }
81
82
  // set up the glyph pixmap cache
83
8.27k
  cacheAssoc = splashFontCacheAssoc;
84
8.27k
  for (cacheSets = splashFontCacheMaxSets;
85
8.27k
       cacheSets > 1 &&
86
8.27k
   glyphSize > splashFontCacheSize / (cacheSets * cacheAssoc);
87
8.27k
       cacheSets >>= 1) ;
88
8.27k
  cache = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize);
89
8.27k
  cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc,
90
8.27k
               sizeof(SplashFontCacheTag));
91
537k
  for (i = 0; i < cacheSets * cacheAssoc; ++i) {
92
529k
    cacheTags[i].mru = i & (cacheAssoc - 1);
93
529k
  }
94
8.27k
}
95
96
8.27k
SplashFont::~SplashFont() {
97
8.27k
  fontFile->decRefCnt();
98
8.27k
  if (cache) {
99
8.27k
    gfree(cache);
100
8.27k
  }
101
8.27k
  if (cacheTags) {
102
8.27k
    gfree(cacheTags);
103
8.27k
  }
104
8.27k
}
105
106
GBool SplashFont::getGlyph(Guint c, int xFrac, int yFrac,
107
591k
         SplashGlyphBitmap *bitmap) {
108
591k
  SplashGlyphBitmap bitmap2;
109
591k
  int size;
110
591k
  Guchar *p;
111
591k
  int i, j, k;
112
113
  // no fractional coordinates for large glyphs or non-anti-aliased
114
  // glyphs
115
591k
  if (!aa || glyphH > 50) {
116
0
    xFrac = yFrac = 0;
117
0
  }
118
119
  // check the cache
120
591k
  if (cache) {
121
591k
    i = (c & (cacheSets - 1)) * cacheAssoc;
122
5.30M
    for (j = 0; j < cacheAssoc; ++j) {
123
4.72M
      if ((cacheTags[i+j].mru & 0x80000000) &&
124
112k
    cacheTags[i+j].c == c &&
125
11.0k
    (int)cacheTags[i+j].xFrac == xFrac &&
126
10.8k
    (int)cacheTags[i+j].yFrac == yFrac) {
127
10.8k
  bitmap->x = cacheTags[i+j].x;
128
10.8k
  bitmap->y = cacheTags[i+j].y;
129
10.8k
  bitmap->w = cacheTags[i+j].w;
130
10.8k
  bitmap->h = cacheTags[i+j].h;
131
97.8k
  for (k = 0; k < cacheAssoc; ++k) {
132
86.9k
    if (k != j &&
133
76.0k
        (cacheTags[i+k].mru & 0x7fffffff) <
134
76.0k
        (cacheTags[i+j].mru & 0x7fffffff)) {
135
5.22k
      ++cacheTags[i+k].mru;
136
5.22k
    }
137
86.9k
  }
138
10.8k
  cacheTags[i+j].mru = 0x80000000;
139
10.8k
  bitmap->aa = aa;
140
10.8k
  bitmap->data = cache + (i+j) * glyphSize;
141
10.8k
  bitmap->freeData = gFalse;
142
10.8k
  return gTrue;
143
10.8k
      }
144
4.72M
    }
145
591k
  } else {
146
0
    i = 0; // make gcc happy
147
0
  }
148
149
  // generate the glyph bitmap
150
580k
  if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) {
151
567k
    return gFalse;
152
567k
  }
153
154
  // if the glyph doesn't fit in the bounding box, return a temporary
155
  // uncached bitmap
156
13.6k
  if (!cache || bitmap2.w > glyphW || bitmap2.h > glyphH) {
157
12.6k
    *bitmap = bitmap2;
158
12.6k
    return gTrue;
159
12.6k
  }
160
161
  // insert glyph pixmap in cache
162
1.02k
  if (aa) {
163
1.02k
    size = bitmap2.w * bitmap2.h;
164
1.02k
  } else {
165
0
    size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
166
0
  }
167
1.02k
  p = NULL; // make gcc happy
168
9.22k
  for (j = 0; j < cacheAssoc; ++j) {
169
8.20k
    if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) {
170
1.02k
      cacheTags[i+j].mru = 0x80000000;
171
1.02k
      cacheTags[i+j].c = c;
172
1.02k
      cacheTags[i+j].xFrac = (short)xFrac;
173
1.02k
      cacheTags[i+j].yFrac = (short)yFrac;
174
1.02k
      cacheTags[i+j].x = bitmap2.x;
175
1.02k
      cacheTags[i+j].y = bitmap2.y;
176
1.02k
      cacheTags[i+j].w = bitmap2.w;
177
1.02k
      cacheTags[i+j].h = bitmap2.h;
178
1.02k
      p = cache + (i+j) * glyphSize;
179
1.02k
      memcpy(p, bitmap2.data, size);
180
7.17k
    } else {
181
7.17k
      ++cacheTags[i+j].mru;
182
7.17k
    }
183
8.20k
  }
184
1.02k
  *bitmap = bitmap2;
185
1.02k
  bitmap->data = p;
186
1.02k
  bitmap->freeData = gFalse;
187
1.02k
  if (bitmap2.freeData) {
188
1.02k
    gfree(bitmap2.data);
189
1.02k
  }
190
1.02k
  return gTrue;
191
13.6k
}