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 
34 struct 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 
SplashFont(SplashFontFile * fontFileA,const SplashCoord * matA,const SplashCoord * textMatA,bool aaA)46 SplashFont::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 
initCache()66 void 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(cacheSets * cacheAssoc, glyphSize);
100     if (cache != nullptr) {
101         cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, 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 
~SplashFont()110 SplashFont::~SplashFont()
111 {
112     fontFile->decRefCnt();
113     if (cache) {
114         gfree(cache);
115     }
116     if (cacheTags) {
117         gfree(cacheTags);
118     }
119 }
120 
getGlyph(int c,int xFrac,int yFrac,SplashGlyphBitmap * bitmap,int x0,int y0,SplashClip * clip,SplashClipResult * clipRes)121 bool 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(x0 - bitmap->x, y0 - bitmap->y, x0 - bitmap->x + bitmap->w - 1, y0 - bitmap->y + bitmap->h - 1);
153 
154             return true;
155         }
156     }
157 
158     // generate the glyph bitmap
159     if (!makeGlyph(c, xFrac, yFrac, &bitmap2, x0, y0, clip, clipRes)) {
160         return false;
161     }
162 
163     if (*clipRes == splashClipAllOutside) {
164         bitmap->freeData = false;
165         if (bitmap2.freeData)
166             gfree(bitmap2.data);
167         return true;
168     }
169 
170     // if the glyph doesn't fit in the bounding box, return a temporary
171     // uncached bitmap
172     if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
173         *bitmap = bitmap2;
174         return true;
175     }
176 
177     // insert glyph pixmap in cache
178     if (aa) {
179         size = bitmap2.w * bitmap2.h;
180     } else {
181         size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
182     }
183     p = nullptr; // make gcc happy
184     if (cacheAssoc == 0) {
185         // we had problems on the malloc of the cache, so ignore it
186         *bitmap = bitmap2;
187     } else {
188         for (j = 0; j < cacheAssoc; ++j) {
189             if ((cacheTags[i + j].mru & 0x7fffffff) == cacheAssoc - 1) {
190                 cacheTags[i + j].mru = 0x80000000;
191                 cacheTags[i + j].c = c;
192                 cacheTags[i + j].xFrac = (short)xFrac;
193                 cacheTags[i + j].yFrac = (short)yFrac;
194                 cacheTags[i + j].x = bitmap2.x;
195                 cacheTags[i + j].y = bitmap2.y;
196                 cacheTags[i + j].w = bitmap2.w;
197                 cacheTags[i + j].h = bitmap2.h;
198                 p = cache + (i + j) * glyphSize;
199                 memcpy(p, bitmap2.data, size);
200             } else {
201                 ++cacheTags[i + j].mru;
202             }
203         }
204         *bitmap = bitmap2;
205         bitmap->data = p;
206         bitmap->freeData = false;
207         if (bitmap2.freeData) {
208             gfree(bitmap2.data);
209         }
210     }
211     return true;
212 }
213