Implement lazy font loading (off by default)

Extracts default.woff2 from binary, embeds fonts.conf,
removes .data files on output.
Use --memory-init-file=0 to remove .mem files on output.
Specify fallbackFont to override default.woff2.
If lazyFileLoading is set to true, use FS.createLazyFile(). This is
off by default, as it depends on correct HTTP headers sent back.

Cherry-picked from: 7988397f91
This commit is contained in:
WeebDataHoarder 2022-06-23 09:37:58 +02:00 committed by Dmitry Lyzo
parent 3df655a9df
commit 06edd4fcde
7 changed files with 39 additions and 14 deletions

View File

@ -155,16 +155,16 @@ all-src:
EMCC_COMMON_ARGS = \ EMCC_COMMON_ARGS = \
$(LDFLAGS) \ $(LDFLAGS) \
-s EXPORTED_FUNCTIONS="['_main', '_malloc']" \ -s EXPORTED_FUNCTIONS="['_main', '_malloc']" \
-s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE="['\$$Browser']" \
-s EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap', 'getValue', 'FS_createPreloadedFile', 'FS_createPath']" \ -s EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap', 'getValue', 'FS_createPreloadedFile', 'FS_createPath']" \
--use-preload-plugins \ --embed-file assets/fonts.conf \
--preload-file assets/default.woff2 \
--preload-file assets/fonts.conf \
-s ALLOW_MEMORY_GROWTH=1 \ -s ALLOW_MEMORY_GROWTH=1 \
-s NO_FILESYSTEM=0 \ -s NO_FILESYSTEM=0 \
--memory-init-file=0 \
--no-heap-copy \ --no-heap-copy \
-o $@ -o $@
dist: src/subtitles-octopus-worker.bc dist/js/subtitles-octopus-worker.js dist/js/subtitles-octopus-worker-legacy.js dist/js/subtitles-octopus.js dist/js/COPYRIGHT dist: src/subtitles-octopus-worker.bc dist/js/subtitles-octopus-worker.js dist/js/subtitles-octopus-worker-legacy.js dist/js/subtitles-octopus.js dist/js/COPYRIGHT dist/js/default.woff2
dist/js/subtitles-octopus-worker.js: src/subtitles-octopus-worker.bc src/pre-worker.js src/SubOctpInterface.js src/post-worker.js build/lib/brotli/js/decode.js dist/js/subtitles-octopus-worker.js: src/subtitles-octopus-worker.bc src/pre-worker.js src/SubOctpInterface.js src/post-worker.js build/lib/brotli/js/decode.js
mkdir -p dist/js mkdir -p dist/js
@ -202,6 +202,9 @@ dist/license/all:
dist/js/COPYRIGHT: dist/license/all dist/js/COPYRIGHT: dist/license/all
cp "$<" "$@" cp "$<" "$@"
dist/js/default.woff2:
cp assets/default.woff2 "$@"
# Clean Tasks # Clean Tasks
clean: clean-dist clean-libs clean-octopus clean: clean-dist clean-libs clean-octopus

View File

@ -114,6 +114,8 @@ When creating an instance of SubtitleOctopus, you can set the following options:
- `fonts`: An array of links to the fonts used in the subtitle. (Optional) - `fonts`: An array of links to the fonts used in the subtitle. (Optional)
- `availableFonts`: Object with all available fonts - Key is font name in lower - `availableFonts`: Object with all available fonts - Key is font name in lower
case, value is link: `{"arial": "/font1.ttf"}` (Optional) case, value is link: `{"arial": "/font1.ttf"}` (Optional)
- `fallbackFont`: URL to override fallback font, for example, with a CJK one. Default fallback font is Liberation Sans (Optional)
- `lazyFileLoading`: A boolean, whether to load files in a lazy way via [FS.createLazyFile()](https://emscripten.org/docs/api_reference/Filesystem-API.html#FS.createLazyFile). [Requires](https://github.com/emscripten-core/emscripten/blob/c7b21c32fef92799da05d15ba1939b6394fe0373/src/library_fs.js#L1679-L1856) `Access-Control-Expose-Headers` for `Accept-Ranges, Content-Length, and Content-Encoding`. If encoding is compressed or length is not set, file will be fully fetched instead of just a HEAD request.
- `timeOffset`: The amount of time the subtitles should be offset from the - `timeOffset`: The amount of time the subtitles should be offset from the
video. (Default: `0`) video. (Default: `0`)
- `onReady`: Function that's called when SubtitlesOctopus is ready. (Optional) - `onReady`: Function that's called when SubtitlesOctopus is ready. (Optional)

View File

@ -6,6 +6,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <string>
#include <ass/ass.h> #include <ass/ass.h>
#include "libass.cpp" #include "libass.cpp"
@ -294,6 +295,8 @@ public:
int status; int status;
std::string defaultFont;
SubtitleOctopus(): ass_library(NULL), ass_renderer(NULL), track(NULL), canvas_w(0), canvas_h(0), status(0), m_is_event_animated(NULL), m_drop_animations(false) { SubtitleOctopus(): ass_library(NULL), ass_renderer(NULL), track(NULL), canvas_w(0), canvas_h(0), status(0), m_is_event_animated(NULL), m_drop_animations(false) {
} }
@ -311,7 +314,11 @@ public:
return m_drop_animations; return m_drop_animations;
} }
void initLibrary(int frame_w, int frame_h) { void initLibrary(int frame_w, int frame_h, char* default_font) {
if (default_font != NULL) {
defaultFont.assign(default_font);
}
ass_library = ass_library_init(); ass_library = ass_library_init();
if (!ass_library) { if (!ass_library) {
fprintf(stderr, "jso: ass_library_init failed!\n"); fprintf(stderr, "jso: ass_library_init failed!\n");
@ -390,11 +397,11 @@ public:
void reloadLibrary() { void reloadLibrary() {
quitLibrary(); quitLibrary();
initLibrary(canvas_w, canvas_h); initLibrary(canvas_w, canvas_h, NULL);
} }
void reloadFonts() { void reloadFonts() {
ass_set_fonts(ass_renderer, "/assets/default.woff2", NULL, ASS_FONTPROVIDER_FONTCONFIG, "/assets/fonts.conf", 1); ass_set_fonts(ass_renderer, defaultFont.c_str(), NULL, ASS_FONTPROVIDER_FONTCONFIG, "/assets/fonts.conf", 1);
} }
void setMargin(int top, int bottom, int left, int right) { void setMargin(int top, int bottom, int left, int right) {

View File

@ -186,7 +186,7 @@ interface SubtitleOctopus {
void setLogLevel(long level); void setLogLevel(long level);
void setDropAnimations(long value); void setDropAnimations(long value);
long getDropAnimations(); long getDropAnimations();
void initLibrary(long frame_w, long frame_h); void initLibrary(long frame_w, long frame_h, DOMString default_font);
void createTrack(DOMString subfile); void createTrack(DOMString subfile);
void createTrackMem(DOMString buf, unsigned long bufsize); void createTrackMem(DOMString buf, unsigned long bufsize);
void removeTrack(); void removeTrack();

View File

@ -33,13 +33,18 @@ self.writeFontToFS = function(font) {
self.fontMap_[font] = true; self.fontMap_[font] = true;
if (!self.availableFonts.hasOwnProperty(font)) return; if (!self.availableFonts.hasOwnProperty(font)) return;
var content = readBinary(self.availableFonts[font]);
Module["FS"].writeFile('/fonts/font' + (self.fontId++) + '-' + self.availableFonts[font].split('/').pop(), content, { self.loadFontFile('font' + (self.fontId++) + '-', self.availableFonts[font]);
encoding: 'binary'
});
}; };
self.loadFontFile = function (fontId, path) {
if (self.lazyFileLoading && path.indexOf("blob:") !== 0) {
Module["FS"].createLazyFile("/fonts", fontId + path.split('/').pop(), path, true, false);
} else {
Module["FS"].createPreloadedFile("/fonts", fontId + path.split('/').pop(), path, true, false);
}
}
/** /**
* Write all font's mentioned in the .ass file to the virtual FS. * Write all font's mentioned in the .ass file to the virtual FS.
* @param {!string} content the file content. * @param {!string} content the file content.
@ -611,6 +616,8 @@ function onMessageFromMainEmscriptenThread(message) {
} }
self.availableFonts = message.data.availableFonts; self.availableFonts = message.data.availableFonts;
self.fallbackFont = message.data.fallbackFont;
self.lazyFileLoading = message.data.lazyFileLoading;
self.debug = message.data.debug; self.debug = message.data.debug;
if (!hasNativeConsole && self.debug) { if (!hasNativeConsole && self.debug) {
console = makeCustomConsole(); console = makeCustomConsole();

View File

@ -88,10 +88,12 @@ Module["preRun"].push(function () {
self.subContent = null; self.subContent = null;
self.loadFontFile(".fallback-", self.fallbackFont);
//Module["FS"].mount(Module["FS"].filesystems.IDBFS, {}, '/fonts'); //Module["FS"].mount(Module["FS"].filesystems.IDBFS, {}, '/fonts');
var fontFiles = self.fontFiles || []; var fontFiles = self.fontFiles || [];
for (var i = 0; i < fontFiles.length; i++) { for (var i = 0; i < fontFiles.length; i++) {
Module["FS_createPreloadedFile"]("/fonts", 'font' + i + '-' + fontFiles[i].split('/').pop(), fontFiles[i], true, true); self.loadFontFile('font' + i + '-', fontFiles[i]);
} }
}); });
@ -100,7 +102,7 @@ Module['onRuntimeInitialized'] = function () {
self.changed = Module._malloc(4); self.changed = Module._malloc(4);
self.octObj.initLibrary(screen.width, screen.height); self.octObj.initLibrary(screen.width, screen.height, "/fonts/.fallback-" + self.fallbackFont.split('/').pop());
self.octObj.setDropAnimations(!!self.dropAllAnimations); self.octObj.setDropAnimations(!!self.dropAllAnimations);
self.octObj.createTrack("/sub.ass"); self.octObj.createTrack("/sub.ass");
self.ass_track = self.octObj.track; self.ass_track = self.octObj.track;

View File

@ -35,6 +35,8 @@ var SubtitlesOctopus = function (options) {
self.canvasParent = null; // (internal) HTML canvas parent element self.canvasParent = null; // (internal) HTML canvas parent element
self.fonts = options.fonts || []; // Array with links to fonts used in sub (optional) self.fonts = options.fonts || []; // Array with links to fonts used in sub (optional)
self.availableFonts = options.availableFonts || []; // Object with all available fonts (optional). Key is font name in lower case, value is link: {"arial": "/font1.ttf"} self.availableFonts = options.availableFonts || []; // Object with all available fonts (optional). Key is font name in lower case, value is link: {"arial": "/font1.ttf"}
self.fallbackFont = options.fallbackFont || 'default.woff2'; // URL to override fallback font, for example, with a CJK one. Default fallback font is Liberation Sans (Optional)
self.lazyFileLoading = options.lazyFileLoading || false; // Load fonts in a lazy way. Requires Access-Control-Expose-Headers for Accept-Ranges, Content-Length, and Content-Encoding. If Content-Encoding is compressed, file will be fully fetched instead of just a HEAD request.
self.onReadyEvent = options.onReady; // Function called when SubtitlesOctopus is ready (optional) self.onReadyEvent = options.onReady; // Function called when SubtitlesOctopus is ready (optional)
if (supportsWebAssembly) { if (supportsWebAssembly) {
self.workerUrl = options.workerUrl || 'subtitles-octopus-worker.js'; // Link to WebAssembly worker self.workerUrl = options.workerUrl || 'subtitles-octopus-worker.js'; // Link to WebAssembly worker
@ -144,6 +146,8 @@ var SubtitlesOctopus = function (options) {
subContent: self.subContent, subContent: self.subContent,
fonts: self.fonts, fonts: self.fonts,
availableFonts: self.availableFonts, availableFonts: self.availableFonts,
fallbackFont: self.fallbackFont,
lazyFileLoading: self.lazyFileLoading,
debug: self.debug, debug: self.debug,
targetFps: self.targetFps, targetFps: self.targetFps,
libassMemoryLimit: self.libassMemoryLimit, libassMemoryLimit: self.libassMemoryLimit,