1//========================================================================
2//
3// SplashFont.cc
4//
5//========================================================================
6
7//========================================================================
8//
9// Modified under the Poppler project - http://poppler.freedesktop.org
10//
11// All changes made under the Poppler project to this file are licensed
12// under GPL version 2 or later
13//
14// Copyright (C) 2007-2008, 2010, 2014, 2019 Albert Astals Cid <aacid@kde.org>
15// Copyright (C) 2018 Oliver Sander <oliver.sander@tu-dresden.de>
16//
17// To see a description of the changes please see the Changelog file that
18// came with your tarball or type make ChangeLog if you are building from git
19//
20//========================================================================
21
22#include <config.h>
23
24#include <climits>
25#include <cstring>
26#include "goo/gmem.h"
27#include "SplashMath.h"
28#include "SplashGlyphBitmap.h"
29#include "SplashFontFile.h"
30#include "SplashFont.h"
31
32//------------------------------------------------------------------------
33
34struct SplashFontCacheTag
35{
36 int c;
37 short xFrac, yFrac; // x and y fractions
38 int mru; // valid bit (0x80000000) and MRU index
39 int x, y, w, h; // offset and size of glyph
40};
41
42//------------------------------------------------------------------------
43// SplashFont
44//------------------------------------------------------------------------
45
46SplashFont::SplashFont(SplashFontFile *fontFileA, const SplashCoord *matA, const SplashCoord *textMatA, bool aaA)
47{
48 fontFile = fontFileA;
49 fontFile->incRefCnt();
50 mat[0] = matA[0];
51 mat[1] = matA[1];
52 mat[2] = matA[2];
53 mat[3] = matA[3];
54 textMat[0] = textMatA[0];
55 textMat[1] = textMatA[1];
56 textMat[2] = textMatA[2];
57 textMat[3] = textMatA[3];
58 aa = aaA;
59
60 cache = nullptr;
61 cacheTags = nullptr;
62
63 xMin = yMin = xMax = yMax = 0;
64}
65
66void SplashFont::initCache()
67{
68 int i;
69
70 // this should be (max - min + 1), but we add some padding to
71 // deal with rounding errors
72 glyphW = xMax - xMin + 3;
73 glyphH = yMax - yMin + 3;
74 if (glyphW > INT_MAX / glyphH) {
75 glyphSize = -1;
76 } else {
77 if (aa) {
78 glyphSize = glyphW * glyphH;
79 } else {
80 glyphSize = ((glyphW + 7) >> 3) * glyphH;
81 }
82 }
83
84 // set up the glyph pixmap cache
85 cacheAssoc = 8;
86 if (glyphSize <= 64) {
87 cacheSets = 32;
88 } else if (glyphSize <= 128) {
89 cacheSets = 16;
90 } else if (glyphSize <= 256) {
91 cacheSets = 8;
92 } else if (glyphSize <= 512) {
93 cacheSets = 4;
94 } else if (glyphSize <= 1024) {
95 cacheSets = 2;
96 } else {
97 cacheSets = 1;
98 }
99 cache = (unsigned char *)gmallocn_checkoverflow(count: cacheSets * cacheAssoc, size: glyphSize);
100 if (cache != nullptr) {
101 cacheTags = (SplashFontCacheTag *)gmallocn(count: cacheSets * cacheAssoc, size: sizeof(SplashFontCacheTag));
102 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
103 cacheTags[i].mru = i & (cacheAssoc - 1);
104 }
105 } else {
106 cacheAssoc = 0;
107 }
108}
109
110SplashFont::~SplashFont()
111{
112 fontFile->decRefCnt();
113 if (cache) {
114 gfree(p: cache);
115 }
116 if (cacheTags) {
117 gfree(p: cacheTags);
118 }
119}
120
121bool SplashFont::getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes)
122{
123 SplashGlyphBitmap bitmap2;
124 int size;
125 unsigned char *p;
126 int i, j, k;
127
128 // no fractional coordinates for large glyphs or non-anti-aliased
129 // glyphs
130 if (!aa || glyphH > 50) {
131 xFrac = yFrac = 0;
132 }
133
134 // check the cache
135 i = (c & (cacheSets - 1)) * cacheAssoc;
136 for (j = 0; j < cacheAssoc; ++j) {
137 if ((cacheTags[i + j].mru & 0x80000000) && cacheTags[i + j].c == c && (int)cacheTags[i + j].xFrac == xFrac && (int)cacheTags[i + j].yFrac == yFrac) {
138 bitmap->x = cacheTags[i + j].x;
139 bitmap->y = cacheTags[i + j].y;
140 bitmap->w = cacheTags[i + j].w;
141 bitmap->h = cacheTags[i + j].h;
142 for (k = 0; k < cacheAssoc; ++k) {
143 if (k != j && (cacheTags[i + k].mru & 0x7fffffff) < (cacheTags[i + j].mru & 0x7fffffff)) {
144 ++cacheTags[i + k].mru;
145 }
146 }
147 cacheTags[i + j].mru = 0x80000000;
148 bitmap->aa = aa;
149 bitmap->data = cache + (i + j) * glyphSize;
150 bitmap->freeData = false;
151
152 *clipRes = clip->testRect(rectXMin: x0 - bitmap->x, rectYMin: y0 - bitmap->y, rectXMax: x0 - bitmap->x + bitmap->w - 1, rectYMax: y0 - bitmap->y + bitmap->h - 1);
153
154 return true;
155 }
156 }
157
158 // generate the glyph bitmap
159 if (!makeGlyph(c, xFrac, yFrac, bitmap: &bitmap2, x0, y0, clip, clipRes)) {
160 return false;
161 }
162
163 if (*clipRes == splashClipAllOutside) {
164 bitmap->freeData = false;
165 if (bitmap2.freeData) {
166 gfree(p: bitmap2.data);
167 }
168 return true;
169 }
170
171 // if the glyph doesn't fit in the bounding box, return a temporary
172 // uncached bitmap
173 if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
174 *bitmap = bitmap2;
175 return true;
176 }
177
178 // insert glyph pixmap in cache
179 if (aa) {
180 size = bitmap2.w * bitmap2.h;
181 } else {
182 size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
183 }
184 p = nullptr; // make gcc happy
185 if (cacheAssoc == 0) {
186 // we had problems on the malloc of the cache, so ignore it
187 *bitmap = bitmap2;
188 } else {
189 for (j = 0; j < cacheAssoc; ++j) {
190 if ((cacheTags[i + j].mru & 0x7fffffff) == cacheAssoc - 1) {
191 cacheTags[i + j].mru = 0x80000000;
192 cacheTags[i + j].c = c;
193 cacheTags[i + j].xFrac = (short)xFrac;
194 cacheTags[i + j].yFrac = (short)yFrac;
195 cacheTags[i + j].x = bitmap2.x;
196 cacheTags[i + j].y = bitmap2.y;
197 cacheTags[i + j].w = bitmap2.w;
198 cacheTags[i + j].h = bitmap2.h;
199 p = cache + (i + j) * glyphSize;
200 memcpy(dest: p, src: bitmap2.data, n: size);
201 } else {
202 ++cacheTags[i + j].mru;
203 }
204 }
205 *bitmap = bitmap2;
206 bitmap->data = p;
207 bitmap->freeData = false;
208 if (bitmap2.freeData) {
209 gfree(p: bitmap2.data);
210 }
211 }
212 return true;
213}
214

source code of poppler/splash/SplashFont.cc