mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 13:56:32 +08:00
1 parent
04d7d2d672
commit
fb4f03465b
11 files changed
+647
-154
No files matched your search
+50
-28
@@ -116,6 +116,8 @@ function createDocumentState() {
|
||||
textFontID: null,
|
||||
textDefaults: { type: "TextObject", size: 16 * 25.4 / 72, color: "#000000", wrap: true, align: "left", paragraphHeight: 0, letterSpacing: 0 },
|
||||
ofdBytes: null,
|
||||
sourcePDF: false,
|
||||
pdfComplete: false,
|
||||
fileName: "ofdgo.ofd",
|
||||
openSeq: 0,
|
||||
pageSeq: 0,
|
||||
@@ -5503,11 +5505,10 @@ async function loadWASM(tab = documentTab()) {
|
||||
if (data.type === "progress") {
|
||||
if (visible) setProgress(data.text, data.percent);
|
||||
} else if (data.type === "conversion") {
|
||||
if (visible && wasmRequests.get(data.id)?.openSeq === state.openSeq && !el.cancelExportButton.disabled) {
|
||||
if (visible && wasmRequests.get(data.id)?.name !== "ofdgoLoadPDF" && wasmRequests.get(data.id)?.openSeq === state.openSeq && !el.cancelExportButton.disabled) {
|
||||
if (data.phase === "open") setProgress("正在读取文档", null);
|
||||
else if (data.phase === "pages") setProgress(data.completed ? `正在整理页面 · ${data.completed} 页` : "正在整理页面", null);
|
||||
else if (data.phase === "convert") setProgress(`正在转换页面 · ${data.completed} / ${data.total} 页`, data.total ? 28 + data.completed / data.total * 22 : null);
|
||||
else if (data.phase === "write.fonts") setProgress("正在处理字体", null);
|
||||
else setProgress("正在生成文档", null);
|
||||
}
|
||||
} else if (data.type === "export") {
|
||||
@@ -5723,7 +5724,6 @@ async function openOFD(file, remote = null, handle = file?.handle) {
|
||||
workspace.tabs.push(tab);
|
||||
const current = () => !tab.closed && tab.opening === request;
|
||||
let accepted = false;
|
||||
let originalSource = null;
|
||||
try {
|
||||
setBusy(true, "正在读取文档", 10, STATUS.opening, tab);
|
||||
await activateDocumentTab(tab);
|
||||
@@ -5742,11 +5742,10 @@ async function openOFD(file, remote = null, handle = file?.handle) {
|
||||
const source = downloaded ? downloaded.file : file;
|
||||
const format = await callTabWASM(tab, "ofdgoDetectFormat", source);
|
||||
if (!current()) return;
|
||||
let bytes = await documentBytes(source);
|
||||
originalSource = bytes;
|
||||
const bytes = await documentBytes(source);
|
||||
tab.state.ofdBytes = bytes;
|
||||
tab.state.sourcePDF = format === "pdf";
|
||||
const name = (downloaded ? downloaded.name : file.name) || `ofdgo.${format}`;
|
||||
let warnings = [];
|
||||
let convertedDoc;
|
||||
if (!current()) {
|
||||
return;
|
||||
@@ -5765,10 +5764,7 @@ async function openOFD(file, remote = null, handle = file?.handle) {
|
||||
}
|
||||
}
|
||||
if (!current()) return;
|
||||
bytes = converted.bytes;
|
||||
tab.state.ofdBytes = bytes;
|
||||
convertedDoc = converted.doc;
|
||||
warnings = JSON.parse(converted.warnings || "null") || [];
|
||||
convertedDoc = converted;
|
||||
}
|
||||
await ensureTabEngine(tab);
|
||||
if (!current()) return;
|
||||
@@ -5776,7 +5772,7 @@ async function openOFD(file, remote = null, handle = file?.handle) {
|
||||
if (!current()) return;
|
||||
tab.state.saveHandle = format === "ofd" && !remote ? handle || null : null;
|
||||
tab.state.saveStamp = tab.state.saveHandle && !nativeHost ? {size: file.size, modified: file.lastModified} : null;
|
||||
tab.state.conversionWarnings = warnings;
|
||||
tab.state.conversionWarnings = [];
|
||||
tab.state.fileName = (name || "ofdgo.ofd").replace(/\.pdf$/i, ".ofd");
|
||||
if (remote && !/\.ofd$/i.test(tab.state.fileName)) tab.state.fileName += ".ofd";
|
||||
tab.state.doc = doc;
|
||||
@@ -5791,6 +5787,7 @@ async function openOFD(file, remote = null, handle = file?.handle) {
|
||||
if (isForegroundDocument(tab) && openSeq === tab.state.openSeq) tab.initialLoad = false;
|
||||
}
|
||||
else tab.status = "文档已打开";
|
||||
if (tab.state.sourcePDF) completePDF(tab);
|
||||
} catch (err) {
|
||||
if (current()) {
|
||||
tab.error = err.name === "AbortError" ? "打开已取消" : err.message;
|
||||
@@ -5807,7 +5804,6 @@ async function openOFD(file, remote = null, handle = file?.handle) {
|
||||
if (nativeHost) await nativeHost.release(source);
|
||||
tab.state.ofdBytes = null;
|
||||
}
|
||||
if (nativeHost && originalSource !== source) await nativeHost.release(originalSource);
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
@@ -6313,22 +6309,15 @@ function requestCredentials(code, openSeq, pdf = false, tab = documentTab()) {
|
||||
async function openWithCredentials(fonts, openSeq, data = state.ofdBytes, importing = false, pdf = false, tab = documentTab()) {
|
||||
const state = tab.state;
|
||||
const callWASM = (name, ...args) => callTabWASM(tab, name, ...args);
|
||||
pdf ||= !importing && state.sourcePDF;
|
||||
const current = () => !tab.closed && (Boolean(tab.opening) || openSeq === state.openSeq);
|
||||
let credentials = null;
|
||||
try {
|
||||
while (current()) {
|
||||
try {
|
||||
if (pdf) {
|
||||
const converted = await callWASM("ofdgoConvertPDF", data, fonts, credentials?.password || null);
|
||||
let accepted = false;
|
||||
try {
|
||||
if (!current()) return converted;
|
||||
converted.doc = await callWASM("ofdgoOpen", converted.bytes, fonts, state.renderAnnotations, credentials);
|
||||
accepted = current();
|
||||
return converted;
|
||||
} finally {
|
||||
if (!accepted && nativeHost) await nativeHost.release(converted.bytes);
|
||||
}
|
||||
state.pdfComplete = false;
|
||||
return await callWASM("ofdgoOpenPDF", data, fonts, credentials?.password || null, state.renderAnnotations);
|
||||
}
|
||||
return importing ? await callWASM("ofdgoLoadImport", data?.nativeFile ? data : data.slice(), credentials)
|
||||
: await callWASM("ofdgoOpen", data, fonts, state.renderAnnotations, credentials);
|
||||
@@ -6444,8 +6433,10 @@ async function openDocument(options = {}) {
|
||||
if (openSeq !== state.openSeq) {
|
||||
return;
|
||||
}
|
||||
wasmWorker.configurePages?.(!state.editorInfo && !doc.encrypted && state.ofdBytes ? {
|
||||
file: state.ofdBytes, fonts, annotations: state.renderAnnotations, document: doc.documentIndex, version: doc.documentVersion
|
||||
const pageFonts = state.sourcePDF && !nativeHost && !state.editorInfo ? await fontManager.files(fontManager.records()) : fonts;
|
||||
if (openSeq !== state.openSeq) return;
|
||||
tab.worker.configurePages?.(!state.editorInfo && !doc.encrypted && state.ofdBytes ? {
|
||||
file: state.ofdBytes, fonts: pageFonts, pdf: state.sourcePDF, fontNames: state.sourcePDF ? [...fontManager.localEntries().keys()] : [], annotations: state.renderAnnotations, document: doc.documentIndex, version: doc.documentVersion
|
||||
} : null);
|
||||
if (options.keepPreview) {
|
||||
pageView.resetPageLoading();
|
||||
@@ -6535,10 +6526,40 @@ async function openDocument(options = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
async function completePDF(tab) {
|
||||
const state = tab.state, source = state.ofdBytes, wasmSeq = state.wasmSeq;
|
||||
if (tab.pdfTask?.wasmSeq === wasmSeq || state.pdfComplete || !state.sourcePDF || !source || state.editorInfo) return;
|
||||
const task = {wasmSeq};
|
||||
tab.pdfTask = task;
|
||||
const current = () => !tab.closed && state.ofdBytes === source && state.wasmSeq === wasmSeq;
|
||||
try {
|
||||
while (current()) {
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
if (!current()) return;
|
||||
const result = await callTabWASM(tab, "ofdgoLoadPDF");
|
||||
if (!current()) return;
|
||||
if (!result.done) continue;
|
||||
state.pdfComplete = true;
|
||||
state.conversionWarnings = JSON.parse(result.warnings || "null") || [];
|
||||
if (!state.editorInfo) Object.assign(state.doc, result.doc);
|
||||
if (isForegroundDocument(tab)) loadDocumentDetails(state.openSeq);
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
if (current() && !err.canceled) {
|
||||
tab.status = err.message;
|
||||
if (isForegroundDocument(tab)) showError(err, false);
|
||||
}
|
||||
} finally {
|
||||
if (tab.pdfTask === task) tab.pdfTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDocumentDetails(openSeq) {
|
||||
const tab = documentTab(), state = tab.state;
|
||||
const callWASM = (name, ...args) => callTabWASM(tab, name, ...args);
|
||||
if (openSeq !== state.openSeq || !state.doc) return;
|
||||
if (state.sourcePDF && !state.pdfComplete && !state.editorInfo) { completePDF(tab); return; }
|
||||
try {
|
||||
const details = await callWASM("ofdgoDocumentInfo");
|
||||
if (openSeq !== state.openSeq) return;
|
||||
@@ -9930,7 +9951,7 @@ async function exportFile(whole, indices = null, value = el.exportFormat.value,
|
||||
if (tab.closed || wasmSeq !== state.wasmSeq) return;
|
||||
setBusy(true, "正在生成文件", null, status, tab);
|
||||
}
|
||||
const readingSave = saving && !state.editorInfo && indices === null && compression.mode === 0;
|
||||
const readingSave = saving && !state.sourcePDF && !state.editorInfo && indices === null && compression.mode === 0;
|
||||
const destination = !nativeHost && file && file === state.saveHandle && state.saveStamp ? {fileHandle: file, saveStamp: state.saveStamp} : file;
|
||||
if (saving && indices === null && !readingSave) {
|
||||
snapshotPrepared = true;
|
||||
@@ -12350,13 +12371,13 @@ async function callTabWASM(tab, name, ...args) {
|
||||
if (name === "ofdgoResources" && workspace.active === tab && resourceElements.Panel.open) resourceManager.requestID = id;
|
||||
wasmRequests.set(id, { name, resolve, reject, openSeq: state.openSeq, tab });
|
||||
if (name === "ofdgoExportMedia") wasmRequests.get(id).mediaID = args[0];
|
||||
if (name === "ofdgoConvertPDF") {
|
||||
if (name === "ofdgoOpenPDF" || state.sourcePDF && !state.editorInfo) {
|
||||
const request = wasmRequests.get(id);
|
||||
request.localFonts = fontManager.localEntries();
|
||||
request.fontData = new Map();
|
||||
args.push([...request.localFonts.keys()]);
|
||||
if (name === "ofdgoOpenPDF") args.push([...request.localFonts.keys()]);
|
||||
}
|
||||
if (name === "ofdgoImportDocuments" || name === "ofdgoImportImages" || name === "ofdgoExportImages" || name === "ofdgoConvertPDF" || name === "ofdgoExportPage" || name === "ofdgoExportDocument" || name === "ofdgoExportAttachment" || name === "ofdgoExportResource" || name === "ofdgoExportVersion" || name === "ofdgoSaveDocument" || name === "ofdgoSaveSigned" || name === "ofdgoImportPages") {
|
||||
if (name === "ofdgoImportDocuments" || name === "ofdgoImportImages" || name === "ofdgoExportImages" || name === "ofdgoOpenPDF" || name === "ofdgoExportPage" || name === "ofdgoExportDocument" || name === "ofdgoExportAttachment" || name === "ofdgoExportResource" || name === "ofdgoExportVersion" || name === "ofdgoSaveDocument" || name === "ofdgoSaveSigned" || name === "ofdgoImportPages") {
|
||||
state.exportRequestID = id;
|
||||
if (visible) {
|
||||
el.cancelExportButton.hidden = false;
|
||||
@@ -12371,6 +12392,7 @@ async function callTabWASM(tab, name, ...args) {
|
||||
}
|
||||
if (name === "ofdgoLoadImport" && ArrayBuffer.isView(args[0]) && !nativeHost) transfer.push(args[0].buffer);
|
||||
const message = {id, name, args};
|
||||
if (name === "ofdgoLoadPDF") message.background = true;
|
||||
if (name === "ofdgoRenderPage" && [...state.pageInFlight.values()].some(task => task.index === args[0] && pageView.pageRenderPriority(task, state) >= 6)) message.preload = true;
|
||||
tab.worker.postMessage(message, transfer);
|
||||
} catch (err) {
|
||||
|
||||
+41
-11
@@ -35,7 +35,7 @@ class BrowserScheduler {
|
||||
}
|
||||
|
||||
priority(task) {
|
||||
return Number(task.worker.batch || this.owner(task.worker, task.data)?.foreground === false) + Number(!!task.data.preload);
|
||||
return Number(task.worker.batch || this.owner(task.worker, task.data)?.foreground === false) + Number(!!task.data.preload || !!task.data.background);
|
||||
}
|
||||
|
||||
submit(worker, data, transfer) {
|
||||
@@ -92,8 +92,8 @@ class BrowserScheduler {
|
||||
const busy = [...task.worker.operations.values()].some(data => data.engineID === task.data.engineID && data.name !== "ofdgoSaveSnapshot");
|
||||
const snapshot = task.data.name === "ofdgoSaveSnapshot" && [...task.worker.operations.values()].some(data => data.engineID === task.data.engineID && data.name === "ofdgoSaveSnapshot");
|
||||
const active = this.active();
|
||||
const interactive = task.worker.primary && this.owner(task.worker, task.data)?.foreground === true && !task.data.preload;
|
||||
const foregroundActive = [...this.workers].some(worker => [...worker.operations.values()].some(data => data.name !== "ofdgoSaveSnapshot" && worker.primary && this.owner(worker, data)?.foreground === true && !data.preload));
|
||||
const interactive = task.worker.primary && this.owner(task.worker, task.data)?.foreground === true && !task.data.preload && !task.data.background;
|
||||
const foregroundActive = [...this.workers].some(worker => [...worker.operations.values()].some(data => data.name !== "ofdgoSaveSnapshot" && worker.primary && this.owner(worker, data)?.foreground === true && !data.preload && !data.background));
|
||||
const continuing = task.worker.primary && [...task.worker.operations.values()].some(data => data.engineID === task.data.engineID);
|
||||
const available = continuing || active < this.limit || interactive && !foregroundActive && active < this.limit + 1;
|
||||
if (busy || snapshot || !available || !task.worker.primary && active && this.memory + (64 << 20) > this.budget) { i++; continue; }
|
||||
@@ -307,6 +307,8 @@ class BrowserEngine {
|
||||
this.primary.onerror = event => this.onerror?.(event);
|
||||
this.primary.onmessageerror = event => this.onmessageerror?.(event);
|
||||
this.requests = new Map();
|
||||
this.fontRequests = new Map();
|
||||
this.primaryPages = new Set();
|
||||
this.slots = new Set();
|
||||
this.sequence = 0;
|
||||
this.revision = 0;
|
||||
@@ -323,8 +325,9 @@ class BrowserEngine {
|
||||
configurePages(source) {
|
||||
const current = this.pageSource;
|
||||
const fonts = (source?.fonts || []).map(font => font?.data !== undefined ? {name:font.name, data:font.data} : font);
|
||||
const sameNames = JSON.stringify(source?.fontNames || []) === JSON.stringify(current?.fontNames || []);
|
||||
const sameFonts = current && fonts.length === current.fonts.length && fonts.every((font, index) => font === current.fonts[index] || font?.data !== undefined && font.name === current.fonts[index]?.name && font.data === current.fonts[index]?.data);
|
||||
if (source && current && source.file === current.file && (source.document || 0) === current.document && (source.version || "") === current.version && source.annotations === current.annotations && source.revision === current.revision && sameFonts) return;
|
||||
if (source && current && source.file === current.file && !!source.pdf === !!current.pdf && (source.document || 0) === current.document && (source.version || "") === current.version && source.annotations === current.annotations && source.revision === current.revision && sameFonts && sameNames) return;
|
||||
this.invalidatePages();
|
||||
if (!source || this.closed) return;
|
||||
this.pageSource = {...source, fonts, document:source.document || 0, version:source.version || ""};
|
||||
@@ -347,6 +350,7 @@ class BrowserEngine {
|
||||
|
||||
invalidatePages() {
|
||||
this.revision++;
|
||||
this.primaryPages.clear();
|
||||
this.source = null;
|
||||
this.pageSource = null;
|
||||
this.parallelism = 1;
|
||||
@@ -358,6 +362,7 @@ class BrowserEngine {
|
||||
closeSlot(slot, error = new DOMException("页面加载已取消", "AbortError")) {
|
||||
if (!this.slots.delete(slot)) return;
|
||||
slot.worker.terminate();
|
||||
for (const [id, request] of this.fontRequests) if (request.worker === slot.worker) this.fontRequests.delete(id);
|
||||
slot.rejectReady(error);
|
||||
for (const pending of slot.pending.values()) pending.reject(error);
|
||||
slot.pending.clear();
|
||||
@@ -378,6 +383,12 @@ class BrowserEngine {
|
||||
if (this.source) this.parallelism = engineScheduler.limit;
|
||||
if (data.type === "ready") { resolve(); return; }
|
||||
if (data.type === "exit") { this.closeSlot(slot, new Error("页面加载失败")); return; }
|
||||
if (data.type === "font") {
|
||||
const request = `${slot.worker.engineID}:${data.request}`;
|
||||
this.fontRequests.set(request, {worker:slot.worker, request:data.request});
|
||||
this.onmessage?.({data:{...data, id:slot.requestID, request}});
|
||||
return;
|
||||
}
|
||||
if (data.type) return;
|
||||
const request = slot.pending.get(data.id);
|
||||
if (!request) return;
|
||||
@@ -389,7 +400,9 @@ class BrowserEngine {
|
||||
});
|
||||
this.slots.add(slot);
|
||||
slot.ready = ready.then(async () => {
|
||||
let opened = await this.callSlot(slot, "ofdgoOpen", [source.file, source.fonts, source.annotations]);
|
||||
let opened = source.pdf
|
||||
? await this.callSlot(slot, "ofdgoOpenPDF", [source.file, source.fonts, null, source.annotations, source.fontNames])
|
||||
: await this.callSlot(slot, "ofdgoOpen", [source.file, source.fonts, source.annotations]);
|
||||
if ((source.document || 0) !== (opened.data.documentIndex || 0)) opened = await this.callSlot(slot, "ofdgoSelectDocument", [source.document]);
|
||||
if ((source.version || "") !== (opened.data.documentVersion || "")) await this.callSlot(slot, "ofdgoSelectVersion", [source.version || ""]);
|
||||
if (this.slots.has(slot)) this.startupTime = performance.now() - started;
|
||||
@@ -409,6 +422,7 @@ class BrowserEngine {
|
||||
}
|
||||
|
||||
pageSlot(data) {
|
||||
if (this.primaryPages.has(data.args[0])) return null;
|
||||
const preferred = [...this.slots].find(slot => !slot.busy && slot.pages.has(data.args[0]));
|
||||
const pending = [...this.requests.values()].filter(slot => slot === null).length - Number(this.requests.has(data.id));
|
||||
if (!preferred && pending <= 0) return null;
|
||||
@@ -440,6 +454,14 @@ class BrowserEngine {
|
||||
|
||||
postMessage(data, transfer) {
|
||||
if (this.closed) return;
|
||||
if (data.type === "font" && typeof data.request === "string") {
|
||||
const request = this.fontRequests.get(data.request);
|
||||
if (request) {
|
||||
this.fontRequests.delete(data.request);
|
||||
request.worker.postMessage({...data, request:request.request}, transfer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!data.type && data.preload && this.pagesPaused) {
|
||||
this.onmessage?.({data:{engineID:this.engineID, id:data.id, ok:false, canceled:true, error:"预加载已暂停"}});
|
||||
return;
|
||||
@@ -451,7 +473,7 @@ class BrowserEngine {
|
||||
return;
|
||||
}
|
||||
if (!data.type && data.name !== "ofdgoRenderPage" && ![
|
||||
"ofdgoDocumentInfo", "ofdgoDocumentVersions", "ofdgoDocumentNavigation", "ofdgoOpenLinks", "ofdgoOutlineLinks", "ofdgoRenderBackends", "ofdgoSVGFontData",
|
||||
"ofdgoLoadPDF", "ofdgoDocumentInfo", "ofdgoDocumentVersions", "ofdgoDocumentNavigation", "ofdgoOpenLinks", "ofdgoOutlineLinks", "ofdgoRenderBackends", "ofdgoSVGFontData",
|
||||
"ofdgoSearchPage", "ofdgoPageTextString", "ofdgoResources", "ofdgoResourceReferences", "ofdgoResourceTargets",
|
||||
"ofdgoResourceLocations", "ofdgoFontPreview", "ofdgoFontFaces", "ofdgoFontFace", "ofdgoMatchFontFiles",
|
||||
"ofdgoImages", "ofdgoStructureTargets", "ofdgoStructureObjects", "ofdgoPackageDocuments", "ofdgoVerifySignatures",
|
||||
@@ -472,11 +494,19 @@ class BrowserEngine {
|
||||
|
||||
renderSlot(slot, data, transfer) {
|
||||
slot.busy = true;
|
||||
slot.requestID = data.id;
|
||||
this.requests.set(data.id, slot);
|
||||
const revision = this.revision;
|
||||
let fallback = false;
|
||||
slot.ready.then(() => this.callSlot(slot, data.name, data.args, !!data.preload)).then(result => {
|
||||
if (revision !== this.revision) throw new DOMException("页面加载已取消", "AbortError");
|
||||
if (this.source.pdf && ((JSON.parse(result.data.annotations || "null") || []).length || result.data.links?.length)) {
|
||||
this.primaryPages.add(data.args[0]);
|
||||
this.requests.set(data.id, this.primary);
|
||||
fallback = true;
|
||||
this.primary.postMessage(data, transfer);
|
||||
return;
|
||||
}
|
||||
slot.lastPage = data.args[0];
|
||||
slot.pages.delete(slot.lastPage);
|
||||
slot.pages.add(slot.lastPage);
|
||||
@@ -612,13 +642,13 @@ class NativeHost {
|
||||
}
|
||||
}
|
||||
|
||||
async decode(value, name = "", key = "", signal) {
|
||||
async decode(value, signal) {
|
||||
const reads = [];
|
||||
const visit = (item, field, replace) => {
|
||||
if (!item || typeof item !== "object" || item instanceof Blob || item instanceof ArrayBuffer || ArrayBuffer.isView(item)) return;
|
||||
if (item.nativeFile) {
|
||||
const file = new NativeFile(item);
|
||||
if (field === "file" || name === "ofdgoConvertPDF" && field === "bytes") replace(file);
|
||||
if (field === "file") replace(file);
|
||||
else reads.push(this.readResource(file, signal).then(bytes => replace(field === "blob" ? new Blob([bytes], {type:item.type}) : new Uint8Array(bytes))));
|
||||
return;
|
||||
}
|
||||
@@ -626,7 +656,7 @@ class NativeHost {
|
||||
if (content && typeof content === "object") visit(content, Array.isArray(item) ? "" : child, result => item[child] = result);
|
||||
}
|
||||
};
|
||||
visit(value, key, result => value = result);
|
||||
visit(value, "", result => value = result);
|
||||
const results = await Promise.allSettled(reads);
|
||||
const failed = results.find(result => result.status === "rejected");
|
||||
if (failed) throw failed.reason;
|
||||
@@ -688,7 +718,7 @@ class NativeHost {
|
||||
return;
|
||||
}
|
||||
if (data.type === "font") return;
|
||||
if (["ofdgoDetectFormat", "ofdgoOpen", "ofdgoConvertPDF"].includes(data.name)) {
|
||||
if (["ofdgoDetectFormat", "ofdgoOpen", "ofdgoOpenPDF"].includes(data.name)) {
|
||||
const input = data.args?.[0];
|
||||
if (input?.nativeFile && !input.temporary) inputs.add(input.nativeFile);
|
||||
}
|
||||
@@ -721,7 +751,7 @@ class NativeHost {
|
||||
let decoded;
|
||||
try {
|
||||
controller.signal.throwIfAborted();
|
||||
decoded = await host.decode(result, data.name, "", controller.signal);
|
||||
decoded = await host.decode(result, controller.signal);
|
||||
controller.signal.throwIfAborted();
|
||||
}
|
||||
catch (error) { await host.release(result); throw error; }
|
||||
|
||||
@@ -229,7 +229,7 @@ export function createPageView(context) {
|
||||
for (const task of context.state.pagePresentQueue.values()) task.resolve(null);
|
||||
context.state.pagePresentQueue.clear();
|
||||
for (const [id, request] of context.wasmRequests) {
|
||||
if (request.tab === context.documentTab() && request.name === "ofdgoRenderPage") context.wasmWorker?.postMessage({ type: "cancel", id });
|
||||
if (request.tab === context.documentTab() && request.name === "ofdgoRenderPage" && (!context.state.sourcePDF || context.state.pdfComplete || context.state.editorInfo)) context.wasmWorker?.postMessage({ type: "cancel", id });
|
||||
}
|
||||
for (const task of context.state.pageInFlight.values()) {
|
||||
task.resolve(null);
|
||||
|
||||
@@ -235,9 +235,9 @@ async function handleMessage(engine, { id, name, args }) {
|
||||
let saveStamp;
|
||||
let channel;
|
||||
const signal = operations.get(id)?.signal;
|
||||
const cancellable = ["ofdgoPreparePrint", "ofdgoLayoutPrint", "ofdgoPrintSide", "ofdgoPrintPDF", "ofdgoResources", "ofdgoPrepareSave", "ofdgoSaveSnapshot", "ofdgoImportDocuments", "ofdgoImportImages", "ofdgoExportImages", "ofdgoConvertPDF", "ofdgoExportPage", "ofdgoExportDocument", "ofdgoExportAttachment", "ofdgoExportResource", "ofdgoExportMedia", "ofdgoExportVersion", "ofdgoSaveDocument", "ofdgoSaveSigned", "ofdgoImportPages"].includes(name);
|
||||
const cancellable = ["ofdgoPreparePrint", "ofdgoLayoutPrint", "ofdgoPrintSide", "ofdgoPrintPDF", "ofdgoResources", "ofdgoPrepareSave", "ofdgoSaveSnapshot", "ofdgoImportDocuments", "ofdgoImportImages", "ofdgoExportImages", "ofdgoOpenPDF", "ofdgoExportPage", "ofdgoExportDocument", "ofdgoExportAttachment", "ofdgoExportResource", "ofdgoExportMedia", "ofdgoExportVersion", "ofdgoSaveDocument", "ofdgoSaveSigned", "ofdgoImportPages"].includes(name);
|
||||
const importing = name === "ofdgoImportPages" || name === "ofdgoImportImages" || name === "ofdgoImportDocuments";
|
||||
const converting = name === "ofdgoConvertPDF";
|
||||
const converting = name === "ofdgoOpenPDF";
|
||||
const saving = name === "ofdgoSaveDocument" || name === "ofdgoSaveSnapshot" || name === "ofdgoSaveSigned";
|
||||
const resources = ["ofdgoPreparePrint", "ofdgoLayoutPrint", "ofdgoPrintSide", "ofdgoPrintPDF", "ofdgoResources", "ofdgoPrepareSave"].includes(name);
|
||||
const key = name === "ofdgoOpen" ? args[3]?.key : name === "ofdgoSaveSigned" || name === "ofdgoLoadImport" ? args[1]?.key : null;
|
||||
@@ -245,7 +245,7 @@ async function handleMessage(engine, { id, name, args }) {
|
||||
const password = converting ? args[2] : name === "ofdgoSetEncryption" ? args[0]?.password : name === "ofdgoOpen" ? args[3]?.password : name === "ofdgoLoadImport" ? args[1]?.password : null;
|
||||
try {
|
||||
signal?.throwIfAborted();
|
||||
if (["ofdgoOpen", "ofdgoLoadImport", "ofdgoConvertPDF"].includes(name) && args[0] instanceof Blob) {
|
||||
if (["ofdgoOpen", "ofdgoOpenPDF", "ofdgoLoadImport"].includes(name) && args[0] instanceof Blob) {
|
||||
const file = args[0], reader = new FileReaderSync();
|
||||
args[0] = {size: file.size, read: (offset, size) => new Uint8Array(reader.readAsArrayBuffer(file.slice(offset, offset + size)))};
|
||||
}
|
||||
@@ -337,10 +337,21 @@ async function handleMessage(engine, { id, name, args }) {
|
||||
if (!saving && args.some(value => value?.mode !== undefined)) args.push(done => finish(done));
|
||||
}
|
||||
}
|
||||
if (engine.pdf && name !== "ofdgoOpenPDF") {
|
||||
channel ||= new MessageChannel();
|
||||
const context = await globalThis.ofdgoEngineCall(engine.id, "ofdgoPDFContext", (phase, completed, total, done) => {
|
||||
postMessage({id, type: "conversion", phase, completed, total});
|
||||
channel.port1.onmessage = () => done("", signal.aborted);
|
||||
channel.port2.postMessage(null);
|
||||
}, (name, done) => requestFont(engine, id, signal, name, done));
|
||||
engine.pdf = JSON.parse(context).data === true;
|
||||
}
|
||||
const started = name === "ofdgoOpen" || name === "ofdgoRenderPage" ? performance.now() : null;
|
||||
const payload = await globalThis.ofdgoEngineCall(engine.id, name, ...args);
|
||||
signal?.throwIfAborted();
|
||||
const result = typeof payload === "string" ? JSON.parse(payload) : payload;
|
||||
if (result.ok && name === "ofdgoOpenPDF") engine.pdf = true;
|
||||
if (result.ok && (name === "ofdgoOpen" || name === "ofdgoLoadPDF" && result.data.done)) engine.pdf = false;
|
||||
if (started !== null && result.ok) result.elapsed = performance.now() - started;
|
||||
if (cancellable && !importing && !converting && !resources && result.ok) {
|
||||
result.data.size = size;
|
||||
|
||||
Reference in new issue
Block a user