feat: PDF viewer

This commit is contained in:
2026-03-06 08:00:57 +01:00
parent ead7d296f7
commit b148f0605a
12 changed files with 3127 additions and 17 deletions
+5
View File
@@ -1484,6 +1484,11 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in
// all the encodingIDs are unicode, so we don't bother to check it
info->index_map = cmap + ttULONG(data+encoding_record+4);
break;
case STBTT_PLATFORM_ID_MAC:
// Accept Mac Roman as fallback (common in PDF subset fonts)
if (info->index_map == 0)
info->index_map = cmap + ttULONG(data+encoding_record+4);
break;
}
}
if (info->index_map == 0)
+33 -14
View File
@@ -63,9 +63,11 @@ struct TrueTypeFont {
GlyphCache caches[4];
int cache_count;
bool valid;
bool em_scaling; // true for PDF embedded fonts: scale by em square, not ascent-descent
bool init(const char* vfs_path) {
valid = false;
em_scaling = false;
data = nullptr;
cache_count = 0;
@@ -97,19 +99,20 @@ struct TrueTypeFont {
return true;
}
GlyphCache* get_cache(int pixel_size) {
// Search existing caches
for (int i = 0; i < cache_count; i++) {
if (caches[i].pixel_size == pixel_size)
return &caches[i];
void init_cache(GlyphCache* gc, int pixel_size) {
// Free any existing glyph bitmaps
for (int i = 0; i < 256; i++) {
if (gc->glyphs[i].bitmap) {
montauk::mfree(gc->glyphs[i].bitmap);
}
gc->glyphs[i].bitmap = nullptr;
gc->glyphs[i].loaded = false;
}
// Create new cache
if (cache_count >= 4) return &caches[0]; // fallback to first
GlyphCache* gc = &caches[cache_count++];
gc->pixel_size = pixel_size;
gc->scale = stbtt_ScaleForPixelHeight(&info, (float)pixel_size);
gc->scale = em_scaling
? stbtt_ScaleForMappingEmToPixels(&info, (float)pixel_size)
: stbtt_ScaleForPixelHeight(&info, (float)pixel_size);
int asc, desc, lg;
stbtt_GetFontVMetrics(&info, &asc, &desc, &lg);
@@ -117,13 +120,29 @@ struct TrueTypeFont {
gc->descent = (int)(desc * gc->scale);
gc->line_gap = (int)(lg * gc->scale);
gc->line_height = gc->ascent - gc->descent + gc->line_gap;
}
for (int i = 0; i < 128; i++) {
gc->glyphs[i].bitmap = nullptr;
gc->glyphs[i].loaded = false;
GlyphCache* get_cache(int pixel_size) {
// Search existing caches
for (int i = 0; i < cache_count; i++) {
if (caches[i].pixel_size == pixel_size)
return &caches[i];
}
return gc;
// Use a free slot if available
if (cache_count < 4) {
GlyphCache* gc = &caches[cache_count++];
init_cache(gc, pixel_size);
return gc;
}
// Evict oldest cache (slot 0) and shift others down
GlyphCache evicted = caches[0];
for (int i = 0; i < 3; i++)
caches[i] = caches[i + 1];
caches[3] = evicted;
init_cache(&caches[3], pixel_size);
return &caches[3];
}
CachedGlyph* get_glyph(GlyphCache* gc, int codepoint) {