All files / client fontCache.js

97.82% Statements 45/46
95% Branches 19/20
100% Functions 10/10
97.82% Lines 45/46

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132              15x               21x             7x         7x 5x 5x     5x   10x     10x 8x 8x   2x                   2x 4x   4x 4x   2x   2x     2x                     8x   8x 6x 6x 6x   5x 2x     1x   2x   1x       5x 5x   4x 3x 2x 2x   1x       1x     3x     1x     2x             3x 2x 2x   1x     1x        
/**
 * Font Cache System
 * Preloads and caches fonts for faster switching
 */
import State from './state.js';
import magicNumbers from './magicNumbers.js';
 
export const FontCache = {
	// In-memory cache for browsers without Cache API
	memoryCache: new Map(),
 
	/**
	 * Check if Cache API is available
	 */
	_hasCacheAPI() {
		return 'caches' in globalThis && globalThis.caches !== undefined;
	},
 
	/**
	 * Preload common fonts
	 */
	async preloadCommonFonts() {
		const commonFonts = [
			magicNumbers.DEFAULT_FONT, // CP437 8x16 - ANSI/CBIN Default
			magicNumbers.NFO_FONT, // Topaz-437 8x16 - NFO default
		];
 
		if (this._hasCacheAPI()) {
			try {
				const cache = await globalThis.caches.open('text0wnz-fonts');
 
				// Preload all common fonts
				await Promise.all(
					commonFonts.map(async fontName => {
						const fontUrl = `${State.fontDir}${fontName}.png`;
 
						// Check if already cached
						if (!(await cache.match(fontUrl))) {
							try {
								await cache.add(fontUrl);
							} catch (err) {
								console.warn(`[FontCache] Failed to preload ${fontName}:`, err);
							}
						}
					}),
				);
			} catch (error) {
				console.error('[FontCache] Error preloading fonts:', error);
			}
		} else {
			// For browsers without Cache API, use fetch and store in memory
			commonFonts.forEach(fontName => {
				const fontUrl = `${State.fontDir}${fontName}.png`;
 
				Eif (!this.memoryCache.has(fontName)) {
					globalThis
						.fetch(fontUrl)
						.then(response => response.blob())
						.then(blob => {
							this.memoryCache.set(fontName, blob);
						})
						.catch(error => {
							console.warn(`[FontCache] Failed to preload ${fontName}:`, error);
						});
				}
			});
		}
	},
 
	/**
	 * Get a font from cache
	 */
	async getFont(fontName) {
		const fontUrl = `${State.fontDir}${fontName}.png`;
 
		if (this._hasCacheAPI()) {
			try {
				const cache = await globalThis.caches.open('text0wnz-fonts');
				const response = await cache.match(fontUrl);
 
				if (response) {
					return response;
				}
			} catch (error) {
				console.warn('[FontCache] Error fetching from cache:', error);
			}
		} else if (this.memoryCache.has(fontName)) {
			// Return from memory cache
			return new globalThis.Response(this.memoryCache.get(fontName));
		}
 
		// Not in cache, fetch and store
		try {
			const response = await globalThis.fetch(fontUrl);
 
			if (response.ok) {
				if (this._hasCacheAPI()) {
					const cache = await globalThis.caches.open('text0wnz-fonts');
					cache.put(fontUrl, response.clone());
				} else {
					response
						.clone()
						.blob()
						.then(blob => {
							this.memoryCache.set(fontName, blob);
						});
				}
				return response;
			}
		} catch (error) {
			console.error('[FontCache] Error fetching font:', error);
		}
 
		return null;
	},
 
	/**
	 * Clear the font cache
	 */
	async clearCache() {
		if (this._hasCacheAPI()) {
			try {
				await globalThis.caches.delete('text0wnz-fonts');
			} catch (error) {
				console.error('[FontCache] Error clearing cache:', error);
			}
		} else {
			this.memoryCache.clear();
		}
	},
};