.. | ||
components | ||
images | ||
locale | ||
favicon.ico | ||
latexworkshop.css | ||
latexworkshop.ts | ||
README.md | ||
tsconfig.json | ||
viewer.css | ||
viewer.html | ||
viewer.js |
Overview
The pdf viewer is based on PDF.js by Mozilla Foundation. Files are from the prebuilt download version. See a related issue.
We load viewer.html
of PDF.js in iframe
in Webview of VS Code through a local Web server. The Webview's content including the iframe
tag is generated by Viewer.getPDFViewerContent. On the browser, we directly load viewer.html
. This architecture enables us to load the same viewer.html
both on VS Code and on the browser.
We control the PDF viewers on both the tab and the browser through WebSockets in the same way. The handler on the server side is defined as Viewer.handler.
We provide additional features by setting up new event listeners in latexworkshop.ts
for DOM objects in viewer.html
. We do not and should not override functions defined by PDF.js.
We can see all the changes, diff, we have made to viewer.js
. We had better find a way to achieve this without modifying viewer.js
.
Restoring the PDF viewer
To restore the PDF viewer at the startup of VS Code, we use the serialization of Webview. The state of the PDF viewer is sent with window.parent.postMessage
in latexworkshop.ts
. We can see the handling of saving the state in HTML generated by Viewer.getPDFViewerContent.
Since it is difficult to map WebSockets to tabs of VS Code, we do not use WebSockets to send the state of the PDF viewer.
Building
JavaScript files, latexworkshop.js
, and others, are generated in ../out/viewer/
from TypeScript files for ES2015 modules.
Limitation
We cannot use Node.js API and VS Code API in latexworkshop.ts
since it is executed in the context of the browser. We cannot import TypeScript files under ../src
either.
Misc
Mozilla asks web developers to reskin viewer.html
because Firefox users would think bugs of the viewer on the web site are ones of Firefox and would report them to the PDF.js team. See link. Our usage does not cause such a problem.
PDFWorker
By default, PDFWorker is recreated every time reopening a PDF file. By setting workerPort
,
we can reuse the PDFWorker:
workerPort: {
value: new Worker('/build/pdf.worker.js'),
kind: OptionKind.WORKER
},
See mozilla/pdf.js/pull/8107 for the details of the setting.
Architecture
flowchart TB
subgraph ExtensionHost["VS Code Extension Host"]
LW["LaTeX Workshop"]
Server["Server for PDF viewer \n(Files and WebSocket)\n127.0.0.1"]
LW --- Server
end
subgraph VSCode["VS Code"]
subgraph WebView["WebView (parent iframe)"]
PDFViewer["PDF viewer (viewer.html)"]
end
end
Server <--> PDFViewer
Server <--> Browser
subgraph Browser
PDFViewerB["PDF viewer (viewer.html)"]
end
VS Code Remote Development
flowchart TB
subgraph Remote["Remote machine or container"]
subgraph ExtensionHost["VS Code Server (Extension Host)"]
LW["LaTeX Workshop"]
Server["Server for PDF viewer\n(Files and WebSocket)\n127.0.0.1 at remote"]
LW --- Server
end
end
subgraph Local["Local machine"]
subgraph VSCode["VS Code"]
PortForwarder["Port forwarder\n127.0.0.1 at local"]
subgraph WebView["WebView (parent iframe)"]
PDFViewer["PDF viewer (viewer.html)"]
end
end
subgraph Browser
PDFViewerB["PDF viewer (viewer.html)"]
end
end
PortForwarder <--> PDFViewer
PortForwarder <--> Browser
Server <--> PortForwarder
Sequence diagrams
Opening a PDF file
sequenceDiagram
participant Viewer as PDF Viewer
participant Server as WebSocket Server
participant WebServer as Web Server
Note over Viewer: load viewer.html
Note over Viewer: load latexworkshop.js
Viewer-)Server: open
Viewer->>WebServer: fetch /config.json
Note over Viewer: load viewer.js
Note over Viewer: webviewerloaded
Viewer->>Viewer: Set PDFViewerApplicationOptions
Note over Viewer: pagesinit
Note over Viewer: documentloaded
Viewer->>Viewer: Apply params
Note over Viewer: pagesloaded
Viewer-)Server: loaded
Reloading a PDF file
sequenceDiagram
participant Viewer as PDF Viewer
participant Server as WebSocket Server
Server-)Viewer: refresh
Note over Viewer: pagesinit
Note over Viewer: documentloaded
Note over Viewer: pagesloaded
Viewer-)Server: loaded
Restoring the internal PDF viewer
sequenceDiagram
participant Viewer as PDF Viewer
participant Server as WebSocket Server
participant WebServer as Web Server
participant Iframe as Parent iframe (VS Code WebView)
Note over Viewer: load viewer.html
Note over Viewer: load latexworkshop.js
Viewer-)Server: open
Viewer->>WebServer: fetch /config.json
Note over Viewer: load viewer.js
Note over Viewer: webviewerloaded
Viewer->>Viewer: Set PDFViewerApplicationOptions
Note over Viewer: pagesinit
Note over Viewer: documentloaded
Viewer->>Viewer: Apply params
Viewer-)+Iframe: initialized
Iframe--)-Viewer: restore_state
Viewer->>Viewer: Restore state
Note over Viewer: pagesloaded
Viewer-)Server: loaded
Forward SyncTeX
sequenceDiagram
participant Viewer as PDF Viewer
participant Server as WebSocket Server
Server-)Viewer: synctex
Backward SyncTeX
sequenceDiagram
participant Viewer as PDF Viewer
participant Server as WebSocket Server
Viewer-)Server: reverse_synctex
When the internal PDF viewer status changed
sequenceDiagram
participant Viewer as PDF Viewer
participant Iframe as Parent iframe (VS Code WebView)
participant ExtensionHost as Extension Host
Viewer-)Iframe: state
Iframe->>Iframe: Store the state
Iframe-)ExtensionHost: state
KeyboardEvent
sequenceDiagram
participant Viewer as PDF Viewer
participant Iframe as Parent iframe (VS Code WebView)
Viewer-)Iframe: KeyboardEvent
Iframe-)Iframe: Dispatch KeyboardEvent
Events emitted by viewer.js
When opening a PDF file. In order.
- webviewerloaded
- DOMContentLoaded (not by
viewer.js
) - baseviewerinit
- pagesinit
- documentloaded
- documentinit
PDF da551cb... [...] (PDF.js: 2.2.228)
(a log message is output)- pagerendered
- pagesloaded
- textlayerrendered
- pagerendered
- textlayerrendered
When reloading a PDF file. In order.
- pagesinit
- documentloaded
- documentinit
PDF da551cb... [...] (PDF.js: 2.2.228)
(a log message is output)- pagerendered
- pagesloaded
- textlayerrendered
- pagerendered
- textlayerrendered
GitHub Codespaces
flowchart TB
subgraph Remote["Remote machine"]
subgraph ExtensionHost["VS Code Server (Extension Host)"]
LW["LaTeX Workshop"]
Server["Server for PDF viewer\n(Files and WebSocket)\n127.0.0.1 at remote"]
LW --- Server
end
PortForwarder
end
GitHub["github.dev"]
GitHubPreview["githubpreview.dev"]
subgraph Browser
subgraph WebView["parent iframe"]
PDFViewer["PDF viewer (viewer.html)"]
end
end
ExtensionHost <--> GitHub
Server <--> PortForwarder
PortForwarder <--> GitHubPreview
GitHub <--> Browser
GitHubPreview <--> PDFViewer