@laminapdf/viewer 0.2.0-alpha.2 → 0.2.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +107 -7
  2. package/dist/client.d.ts +51 -3
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +94 -30
  5. package/dist/client.js.map +1 -1
  6. package/dist/find/controller.d.ts +73 -0
  7. package/dist/find/controller.d.ts.map +1 -0
  8. package/dist/find/controller.js +227 -0
  9. package/dist/find/controller.js.map +1 -0
  10. package/dist/find/fold.d.ts +23 -0
  11. package/dist/find/fold.d.ts.map +1 -0
  12. package/dist/find/fold.js +99 -0
  13. package/dist/find/fold.js.map +1 -0
  14. package/dist/find/page.d.ts +44 -0
  15. package/dist/find/page.d.ts.map +1 -0
  16. package/dist/find/page.js +173 -0
  17. package/dist/find/page.js.map +1 -0
  18. package/dist/index.d.ts +7 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +2 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/layers/box.d.ts +10 -0
  23. package/dist/layers/box.d.ts.map +1 -0
  24. package/dist/layers/box.js +19 -0
  25. package/dist/layers/box.js.map +1 -0
  26. package/dist/layers/highlight-layer.d.ts +31 -0
  27. package/dist/layers/highlight-layer.d.ts.map +1 -0
  28. package/dist/layers/highlight-layer.js +95 -0
  29. package/dist/layers/highlight-layer.js.map +1 -0
  30. package/dist/layers/spans.d.ts +42 -0
  31. package/dist/layers/spans.d.ts.map +1 -0
  32. package/dist/layers/spans.js +121 -0
  33. package/dist/layers/spans.js.map +1 -0
  34. package/dist/layers/structure-layer.d.ts +15 -0
  35. package/dist/layers/structure-layer.d.ts.map +1 -0
  36. package/dist/layers/structure-layer.js +152 -0
  37. package/dist/layers/structure-layer.js.map +1 -0
  38. package/dist/layers/text-layer.d.ts +53 -0
  39. package/dist/layers/text-layer.d.ts.map +1 -0
  40. package/dist/layers/text-layer.js +292 -0
  41. package/dist/layers/text-layer.js.map +1 -0
  42. package/dist/layout/range.d.ts +3 -0
  43. package/dist/layout/range.d.ts.map +1 -0
  44. package/dist/layout/range.js +5 -0
  45. package/dist/layout/range.js.map +1 -0
  46. package/dist/network/watch.d.ts +30 -0
  47. package/dist/network/watch.d.ts.map +1 -0
  48. package/dist/network/watch.js +181 -0
  49. package/dist/network/watch.js.map +1 -0
  50. package/dist/protocol.d.ts +127 -2
  51. package/dist/protocol.d.ts.map +1 -1
  52. package/dist/protocol.js +2 -2
  53. package/dist/protocol.js.map +1 -1
  54. package/dist/render/tiles.d.ts +43 -3
  55. package/dist/render/tiles.d.ts.map +1 -1
  56. package/dist/render/tiles.js +62 -10
  57. package/dist/render/tiles.js.map +1 -1
  58. package/dist/source/http-range.d.ts +59 -0
  59. package/dist/source/http-range.d.ts.map +1 -0
  60. package/dist/source/http-range.js +284 -0
  61. package/dist/source/http-range.js.map +1 -0
  62. package/dist/thumbnails/strip.d.ts +37 -0
  63. package/dist/thumbnails/strip.d.ts.map +1 -0
  64. package/dist/thumbnails/strip.js +313 -0
  65. package/dist/thumbnails/strip.js.map +1 -0
  66. package/dist/view/budgets.d.ts +29 -0
  67. package/dist/view/budgets.d.ts.map +1 -0
  68. package/dist/view/budgets.js +63 -0
  69. package/dist/view/budgets.js.map +1 -0
  70. package/dist/view/touch.d.ts +71 -0
  71. package/dist/view/touch.d.ts.map +1 -0
  72. package/dist/view/touch.js +220 -0
  73. package/dist/view/touch.js.map +1 -0
  74. package/dist/view/viewer.d.ts +42 -1
  75. package/dist/view/viewer.d.ts.map +1 -1
  76. package/dist/view/viewer.js +433 -69
  77. package/dist/view/viewer.js.map +1 -1
  78. package/dist/worker/document.d.ts +33 -1
  79. package/dist/worker/document.d.ts.map +1 -1
  80. package/dist/worker/document.js +181 -24
  81. package/dist/worker/document.js.map +1 -1
  82. package/dist/worker/entry.d.ts +1 -1
  83. package/dist/worker/entry.d.ts.map +1 -1
  84. package/dist/worker/entry.js +3 -1
  85. package/dist/worker/entry.js.map +1 -1
  86. package/dist/worker/find.d.ts +7 -0
  87. package/dist/worker/find.d.ts.map +1 -0
  88. package/dist/worker/find.js +59 -0
  89. package/dist/worker/find.js.map +1 -0
  90. package/dist/worker/methods.d.ts.map +1 -1
  91. package/dist/worker/methods.js +31 -4
  92. package/dist/worker/methods.js.map +1 -1
  93. package/dist/worker/navigation.d.ts +6 -0
  94. package/dist/worker/navigation.d.ts.map +1 -0
  95. package/dist/worker/navigation.js +16 -0
  96. package/dist/worker/navigation.js.map +1 -0
  97. package/dist/worker/network.d.ts +4 -0
  98. package/dist/worker/network.d.ts.map +1 -0
  99. package/dist/worker/network.js +24 -0
  100. package/dist/worker/network.js.map +1 -0
  101. package/dist/worker/render.d.ts +5 -2
  102. package/dist/worker/render.d.ts.map +1 -1
  103. package/dist/worker/render.js +14 -7
  104. package/dist/worker/render.js.map +1 -1
  105. package/dist/worker/text.d.ts +17 -0
  106. package/dist/worker/text.d.ts.map +1 -0
  107. package/dist/worker/text.js +75 -0
  108. package/dist/worker/text.js.map +1 -0
  109. package/dist/zoom/destination.d.ts +18 -0
  110. package/dist/zoom/destination.d.ts.map +1 -0
  111. package/dist/zoom/destination.js +56 -0
  112. package/dist/zoom/destination.js.map +1 -0
  113. package/package.json +6 -5
@@ -0,0 +1,59 @@
1
+ // Find in the document Web Worker: a call searches a few pages and returns each page's matches as
2
+ // quads in page space. The viewer's find controller asks for the next pages only once a call
3
+ // returns, at `background` priority, so renders run between calls and a new query simply stops
4
+ // asking. Each page's searchable text stays in a cache of its own (32 MB at most), so typing a
5
+ // longer query searches pages already read without reading their text again; a page's glyphs are
6
+ // read again only where it has matches.
7
+ import { matchRanges, quadsOfMatches, searchText, snippetOf } from "../find/page.js";
8
+ import { current } from "./document.js";
9
+ import { pageGlyphs } from "./text.js";
10
+ /** The cache's budget, in bytes of UTF-16 text and glyph maps. */
11
+ const SEARCH_CACHE_BYTES = 32 * 1024 * 1024;
12
+ const cache = new Map();
13
+ let cacheBytes = 0;
14
+ const bytesOf = (s) => s.text.length * 2 + s.lo.byteLength + s.hi.byteLength + s.runOf.byteLength;
15
+ /** Page `index`'s searchable text, cached by document and page. */
16
+ async function searchable(index, signal) {
17
+ const key = `${current().id}:${index}`;
18
+ const hit = cache.get(key);
19
+ if (hit !== undefined) {
20
+ cache.delete(key);
21
+ cache.set(key, hit);
22
+ return hit;
23
+ }
24
+ const search = searchText(await pageGlyphs(index, signal, false));
25
+ cache.set(key, search);
26
+ cacheBytes += bytesOf(search);
27
+ for (const [old, value] of cache) {
28
+ if (cacheBytes <= SEARCH_CACHE_BYTES)
29
+ break;
30
+ cache.delete(old);
31
+ cacheBytes -= bytesOf(value);
32
+ }
33
+ return search;
34
+ }
35
+ /** The matches of `query` on each of `pages`, in that order. */
36
+ export async function find(query, options, pages, signal) {
37
+ const out = [];
38
+ for (const page of pages) {
39
+ signal.throwIfAborted();
40
+ const search = await searchable(page, signal);
41
+ const empty = search.text.trim() === "";
42
+ // Most pages have no match: the glyphs are read again only for a page that has one.
43
+ const { folded, ranges } = matchRanges(search, query, options);
44
+ const quads = ranges.length === 0 ? [] : quadsOfMatches(await pageGlyphs(page, signal, false), search, folded, ranges);
45
+ out.push({
46
+ page,
47
+ matches: quads.map((q) => [...q]),
48
+ snippets: ranges.map((r) => snippetOf(search, folded, r)),
49
+ ...(empty ? { noText: true } : {}),
50
+ });
51
+ }
52
+ return out;
53
+ }
54
+ /** Forgets every page's searchable text: the document closed. */
55
+ export function forgetSearch() {
56
+ cache.clear();
57
+ cacheBytes = 0;
58
+ }
59
+ //# sourceMappingURL=find.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find.js","sourceRoot":"","sources":["../../src/worker/find.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../../src/worker/methods.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAKpE,2EAA2E;AAC3E,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAWnE,CAAC"}
1
+ {"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../../src/worker/methods.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAUpE,2EAA2E;AAC3E,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAmCnE,CAAC"}
@@ -1,18 +1,45 @@
1
- // The viewer's methods on the document worker (C3a): the extension `entry.ts` serves, and test
1
+ // The viewer's methods on the document worker: the extension `entry.ts` serves, and test
2
2
  // workers too, which add their own hooks on top so none ships.
3
- import { closeDocument, current, initBackend, openDocument } from "./document.js";
3
+ import { closeDocument, current, initBackend, openDocument, workerMemory } from "./document.js";
4
+ import { find, forgetSearch } from "./find.js";
5
+ import { namedDestination, outline } from "./navigation.js";
6
+ import { networkLog } from "./network.js";
4
7
  import { render, reply } from "./render.js";
8
+ import { forgetText, pageText, replyText, structure } from "./text.js";
5
9
  /** The viewer's worker methods, by name (see `Methods` in protocol.ts). */
6
10
  export const viewerMethods = {
7
11
  initBackend: { run: ([init]) => initBackend(init) },
8
12
  openDocument: {
9
13
  run: ([source, options], { signal }) => openDocument(source, options, signal),
10
14
  },
11
- closeDocument: { run: () => closeDocument() },
12
- pageInfo: { run: ([index]) => current().model.pageInfo(index) },
15
+ closeDocument: {
16
+ run: () => {
17
+ forgetText();
18
+ forgetSearch();
19
+ return closeDocument();
20
+ },
21
+ },
22
+ pageInfo: {
23
+ run: ([index], { signal }) => {
24
+ const { model } = current();
25
+ return model.ensure(() => model.pageInfo(index), { signal });
26
+ },
27
+ },
13
28
  render: {
14
29
  run: ([request, id], { signal }) => render(request, id, signal),
15
30
  reply: (tile) => reply(tile),
16
31
  },
32
+ memory: { run: () => workerMemory() },
33
+ networkLog: { run: () => networkLog() },
34
+ pageText: {
35
+ run: ([index], { signal }) => pageText(index, signal),
36
+ reply: (text) => replyText(text),
37
+ },
38
+ structure: { run: (_params, { signal }) => structure(signal) },
39
+ find: {
40
+ run: ([query, options, pages], { signal }) => find(query, options, pages, signal),
41
+ },
42
+ outline: { run: (_params, { signal }) => outline(signal) },
43
+ namedDestination: { run: ([name], { signal }) => namedDestination(name, signal) },
17
44
  };
18
45
  //# sourceMappingURL=methods.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"methods.js","sourceRoot":"","sources":["../../src/worker/methods.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,+DAA+D;AAK/D,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAE5C,2EAA2E;AAC3E,MAAM,CAAC,MAAM,aAAa,GAA8C;IACtE,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,IAAmB,CAAC,EAAE;IAClE,YAAY,EAAE;QACZ,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,MAAoB,EAAE,OAA4B,EAAE,MAAM,CAAC;KACjH;IACD,aAAa,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE;IAC7C,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAe,CAAC,EAAE;IACzE,MAAM,EAAE;QACN,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,OAAwB,EAAE,EAAY,EAAE,MAAM,CAAC;QAC1F,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAmC,CAAC;KAC5D;CACF,CAAC"}
1
+ {"version":3,"file":"methods.js","sourceRoot":"","sources":["../../src/worker/methods.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { OutlineNode, Target } from "@laminapdf/sdk";
2
+ /** The outline's top-level items, each with its children; empty without one. */
3
+ export declare function outline(signal: AbortSignal): Promise<OutlineNode[]>;
4
+ /** Where the named destination `name` goes, or `undefined` when the document has no such name. */
5
+ export declare function namedDestination(name: string, signal: AbortSignal): Promise<Target | undefined>;
6
+ //# sourceMappingURL=navigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/worker/navigation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAG1D,gFAAgF;AAChF,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAGzE;AAED,kGAAkG;AAClG,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAGrG"}
@@ -0,0 +1,16 @@
1
+ // Moving through the open document: its outline and named destinations, read by Lamina PDF in the
2
+ // worker (the extract module, which the text layer loads too), each target a page and a view in
3
+ // page space. The outline is read when a reader first asks for it, since it can hold thousands of
4
+ // items.
5
+ import { textModel } from "./document.js";
6
+ /** The outline's top-level items, each with its children; empty without one. */
7
+ export async function outline(signal) {
8
+ const model = await textModel(signal);
9
+ return model.ensure(() => model.outline(), { signal });
10
+ }
11
+ /** Where the named destination `name` goes, or `undefined` when the document has no such name. */
12
+ export async function namedDestination(name, signal) {
13
+ const model = await textModel(signal);
14
+ return model.ensure(() => model.namedDestination(name), { signal });
15
+ }
16
+ //# sourceMappingURL=navigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/worker/navigation.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,gGAAgG;AAChG,kGAAkG;AAClG,SAAS;AAGT,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,MAAmB;IAC/C,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IACtC,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,kGAAkG;AAClG,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,MAAmB;IACtE,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IACtC,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { WorkerNetworkLog } from "../protocol.js";
2
+ /** Everything the worker has requested, and had blocked, since it started. */
3
+ export declare function networkLog(): WorkerNetworkLog;
4
+ //# sourceMappingURL=network.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/worker/network.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAkC,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAmBvF,8EAA8E;AAC9E,wBAAgB,UAAU,IAAI,gBAAgB,CAE7C"}
@@ -0,0 +1,24 @@
1
+ // The document worker's network log (ADR 0011, R13). Imported first by entry.ts, so the wrappers
2
+ // are in place before any other module of the worker can capture an unwrapped `fetch`. Every
3
+ // request and every blocked request is kept (the page asks for them all with `networkLog`, so
4
+ // nothing sent before the page listened is lost) and posted as it happens (`network` and
5
+ // `csp-violation` events). Each event carries its index in the log, so the page can merge the two
6
+ // without counting a request twice.
7
+ import { emit } from "@laminapdf/sdk/worker/server";
8
+ import { watchNetwork } from "../network/watch.js";
9
+ const worker = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
10
+ const requests = [];
11
+ const violations = [];
12
+ watchNetwork(globalThis, {
13
+ request(record) {
14
+ emit("network", { worker, index: requests.push(record) - 1, record });
15
+ },
16
+ violation(violation) {
17
+ emit("csp-violation", { worker, index: violations.push(violation) - 1, violation });
18
+ },
19
+ }, "worker");
20
+ /** Everything the worker has requested, and had blocked, since it started. */
21
+ export function networkLog() {
22
+ return { worker, requests: [...requests], violations: [...violations] };
23
+ }
24
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/worker/network.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,6FAA6F;AAC7F,8FAA8F;AAC9F,yFAAyF;AACzF,kGAAkG;AAClG,oCAAoC;AAEpC,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AACvF,MAAM,QAAQ,GAAoB,EAAE,CAAC;AACrC,MAAM,UAAU,GAAsB,EAAE,CAAC;AAEzC,YAAY,CACV,UAAU,EACV;IACE,OAAO,CAAC,MAAM;QACZ,IAAI,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,SAAS,CAAC,SAAS;QACjB,IAAI,CAAC,eAAe,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;IACtF,CAAC;CACF,EACD,QAAQ,CACT,CAAC;AAEF,8EAA8E;AAC9E,MAAM,UAAU,UAAU;IACxB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC;AAC1E,CAAC"}
@@ -1,7 +1,10 @@
1
1
  import type { RenderedTile, RenderRequest } from "@laminapdf/render";
2
2
  import { type RenderedBitmap } from "../protocol.js";
3
- /** Renders `request` on document `id` (a render queued for a document since replaced is `disposed`). */
4
- export declare function render(request: RenderRequest, id: number, signal: AbortSignal): RenderedTile;
3
+ /**
4
+ * Renders `request` on document `id` (a render queued for a document since replaced is
5
+ * `disposed`). A remote document's render fetches the bytes it meets missing and draws again.
6
+ */
7
+ export declare function render(request: RenderRequest, id: number, signal: AbortSignal): Promise<RenderedTile>;
5
8
  /** One caller's bitmap of `tile`. */
6
9
  export declare function reply(tile: RenderedTile): Promise<[RenderedBitmap, Transferable[]]>;
7
10
  //# sourceMappingURL=render.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/worker/render.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,EAAE,KAAK,cAAc,EAAa,MAAM,gBAAgB,CAAC;AAGhE,wGAAwG;AACxG,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,YAAY,CAM5F;AAED,qCAAqC;AACrC,wBAAsB,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC,CAKzF"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/worker/render.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,EAAE,KAAK,cAAc,EAAa,MAAM,gBAAgB,CAAC;AAGhE;;;GAGG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAUrG;AAED,qCAAqC;AACrC,wBAAsB,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC,CAKzF"}
@@ -1,16 +1,23 @@
1
- // Rendering in the document worker (C3a, ADR 0009 §4): the backend draws straight-alpha RGBA, the
1
+ // Rendering in the document worker (ADR 0009 §4): the backend draws straight-alpha RGBA, the
2
2
  // worker makes an ImageBitmap of it and transfers it, so the page never copies pixels. A
3
3
  // coalesced render is drawn once; each caller gets its own bitmap of the same pixels.
4
4
  import { emit } from "@laminapdf/sdk/worker/server";
5
5
  import { renderKey } from "../protocol.js";
6
- import { current } from "./document.js";
7
- /** Renders `request` on document `id` (a render queued for a document since replaced is `disposed`). */
6
+ import { current, filling } from "./document.js";
7
+ /**
8
+ * Renders `request` on document `id` (a render queued for a document since replaced is
9
+ * `disposed`). A remote document's render fetches the bytes it meets missing and draws again.
10
+ */
8
11
  export function render(request, id, signal) {
9
12
  const doc = current(id);
10
- // The client starts its timers now (not while the render waits), and the perf harness (C3c)
11
- // sees what the worker is busy with.
12
- emit("render-start", { page: request.page, scale: request.scale, key: renderKey(request, id) });
13
- return doc.render.render(request, { signal });
13
+ const key = renderKey(request, id);
14
+ const draw = () => {
15
+ // The client starts its timers now (not while the render waits or fetches), and a
16
+ // performance test can see what the worker is busy with.
17
+ emit("render-start", { page: request.page, scale: request.scale, key });
18
+ return doc.render.render(request, { signal });
19
+ };
20
+ return filling(doc.remote, draw, signal, () => emit("render-fetching", { key }));
14
21
  }
15
22
  /** One caller's bitmap of `tile`. */
16
23
  export async function reply(tile) {
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/worker/render.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,yFAAyF;AACzF,sFAAsF;AAGtF,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AACpD,OAAO,EAAuB,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,wGAAwG;AACxG,MAAM,UAAU,MAAM,CAAC,OAAsB,EAAE,EAAU,EAAE,MAAmB;IAC5E,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IACxB,4FAA4F;IAC5F,qCAAqC;IACrC,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IAChG,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,qCAAqC;AACrC,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAkB;IAC5C,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACvC,6FAA6F;IAC7F,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7E,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/worker/render.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,yFAAyF;AACzF,sFAAsF;AAGtF,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AACpD,OAAO,EAAuB,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAEjD;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,OAAsB,EAAE,EAAU,EAAE,MAAmB;IAC5E,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IACxB,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,kFAAkF;QAClF,yDAAyD;QACzD,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACxE,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAChD,CAAC,CAAC;IACF,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;AACnF,CAAC;AAED,qCAAqC;AACrC,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAkB;IAC5C,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACvC,6FAA6F;IAC7F,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7E,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { PageGlyphs } from "../find/page.js";
2
+ import type { PageTextData, StructureData } from "../protocol.js";
3
+ /** Page `index`'s text runs and glyph quads (cached; `signal` stops a read of pending data). */
4
+ export declare function pageText(index: number, signal: AbortSignal): Promise<PageTextData>;
5
+ /**
6
+ * Page `index`'s runs, quads and glyph text, from the cache or read now. `keep: false` (find)
7
+ * reads a page without caching it, so a search through every page never pushes out the text of
8
+ * the pages in view.
9
+ */
10
+ export declare function pageGlyphs(index: number, signal: AbortSignal, keep?: boolean): Promise<PageGlyphs>;
11
+ /** One caller's answer: its own copy of the quads, transferred. */
12
+ export declare function replyText(data: PageTextData): [PageTextData, Transferable[]];
13
+ /** Whether the document says it is tagged, and its structure tree when it has one. */
14
+ export declare function structure(signal: AbortSignal): Promise<StructureData>;
15
+ /** Forgets every page's text: the document closed. */
16
+ export declare function forgetText(): void;
17
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/worker/text.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAe,MAAM,gBAAgB,CAAC;AAY/E,gGAAgG;AAChG,wBAAsB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAGxF;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,UAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAgCrG;AAED,mEAAmE;AACnE,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,CAAC,CAG5E;AAED,sFAAsF;AACtF,wBAAsB,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAK3E;AAED,sDAAsD;AACtD,wBAAgB,UAAU,IAAI,IAAI,CAEjC"}
@@ -0,0 +1,75 @@
1
+ // A page's text for the text layer, read by Lamina PDF in the worker (ADR 0004's two-parsers rule:
2
+ // text geometry comes from Lamina PDF, never from the renderer). Runs cross as small records and
3
+ // every glyph's quad in one Float32Array, which each caller gets its own copy of to transfer, so a
4
+ // page of thousands of glyphs is three objects, not thousands. The last pages read are kept, since
5
+ // a page scrolled back into view asks again.
6
+ import { current, textModel } from "./document.js";
7
+ /** How many pages' text stay cached (a screenful of pages and the margin, at most zoom). */
8
+ const CACHED_PAGES = 24;
9
+ /**
10
+ * The cache, by document ID and page: another document never reads one's pages, and the oldest
11
+ * go. Each page keeps its glyphs' text too, for find; only the runs and quads reach the page.
12
+ */
13
+ const cache = new Map();
14
+ /** Page `index`'s text runs and glyph quads (cached; `signal` stops a read of pending data). */
15
+ export async function pageText(index, signal) {
16
+ const { runs, quads } = await pageGlyphs(index, signal);
17
+ return { runs, quads };
18
+ }
19
+ /**
20
+ * Page `index`'s runs, quads and glyph text, from the cache or read now. `keep: false` (find)
21
+ * reads a page without caching it, so a search through every page never pushes out the text of
22
+ * the pages in view.
23
+ */
24
+ export async function pageGlyphs(index, signal, keep = true) {
25
+ const { id } = current();
26
+ const key = `${id}:${index}`;
27
+ const cached = cache.get(key);
28
+ if (cached !== undefined) {
29
+ // Most recently used last, so the oldest goes first.
30
+ cache.delete(key);
31
+ cache.set(key, cached);
32
+ return cached;
33
+ }
34
+ signal.throwIfAborted();
35
+ const model = await textModel(signal);
36
+ const text = await model.ensure(() => model.page(index).text(), { signal });
37
+ const runs = text.runs.map((run) => ({
38
+ text: run.text,
39
+ size: run.size,
40
+ vertical: run.vertical,
41
+ actualText: run.actualText,
42
+ invisible: run.invisible,
43
+ glyphRange: run.glyphRange,
44
+ ...(run.mcid === undefined ? {} : { mcid: run.mcid }),
45
+ }));
46
+ // The arrays are this worker's own (the SDK copied them out of WebAssembly memory).
47
+ const { quads, glyphText, glyphOffsets } = text.buffers;
48
+ const data = { runs, quads, glyphText, glyphOffsets };
49
+ if (!keep)
50
+ return data;
51
+ cache.set(key, data);
52
+ for (const old of cache.keys()) {
53
+ if (cache.size <= CACHED_PAGES)
54
+ break;
55
+ cache.delete(old);
56
+ }
57
+ return data;
58
+ }
59
+ /** One caller's answer: its own copy of the quads, transferred. */
60
+ export function replyText(data) {
61
+ const copy = { ...data, quads: data.quads.slice() };
62
+ return [copy, [copy.quads.buffer]];
63
+ }
64
+ /** Whether the document says it is tagged, and its structure tree when it has one. */
65
+ export async function structure(signal) {
66
+ const model = await textModel(signal);
67
+ const tagged = await model.ensure(() => model.isTagged, { signal });
68
+ const tree = await model.ensure(() => model.structureTree(), { signal });
69
+ return tree === undefined ? { tagged } : { tagged, tree };
70
+ }
71
+ /** Forgets every page's text: the document closed. */
72
+ export function forgetText() {
73
+ cache.clear();
74
+ }
75
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/worker/text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Target } from "@laminapdf/sdk";
2
+ import { type PageSize, type Rotation } from "../layout/page-layout.js";
3
+ import { type Viewport, type Zoom } from "./zoom.js";
4
+ /** Where to go: the zoom (`undefined` keeps the current one), and the page point for the viewport's top-left. */
5
+ export interface DestinationView {
6
+ readonly zoom: Zoom | undefined;
7
+ readonly page: number;
8
+ /** Fraction of the page box on screen across (0..1); `undefined` keeps the horizontal scroll. */
9
+ readonly x: number | undefined;
10
+ /** Fraction down; `undefined` is the page's top. */
11
+ readonly y: number | undefined;
12
+ }
13
+ /**
14
+ * The view for `target` on a page of `size` (points, `/Rotate` applied) shown at `rotation`, in a
15
+ * `viewport` with `gap` CSS px around pages. A coordinate off the page is clamped onto it.
16
+ */
17
+ export declare function destinationView(target: Target, size: PageSize, rotation: Rotation, viewport: Viewport, gap: number): DestinationView;
18
+ //# sourceMappingURL=destination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destination.d.ts","sourceRoot":"","sources":["../../src/zoom/destination.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAW,MAAM,0BAA0B,CAAC;AACjF,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAErE,iHAAiH;AACjH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iGAAiG;IACjG,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,oDAAoD;IACpD,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAmBD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,GACV,eAAe,CA+BjB"}
@@ -0,0 +1,56 @@
1
+ // Where a destination (ISO 32000-2 §12.3.2.2, Table 149) puts the view: Lamina PDF gives its page
2
+ // and its coordinates in page space (points from the displayed page's top-left, `/Rotate`
3
+ // applied); this turns them by the view's own rotation into fractions of the page box on screen,
4
+ // and its fit into a zoom. Fits are read as pdf.js reads them: `fit-width` fits the viewport's
5
+ // width whichever way the page is turned.
6
+ import { rotated } from "../layout/page-layout.js";
7
+ import { percentOfScale } from "./zoom.js";
8
+ /** Fractions (`x`, `y`) of the unturned page turned clockwise by `rotation`. */
9
+ function turn([x, y], rotation) {
10
+ const flip = (v) => (v === undefined ? undefined : 1 - v);
11
+ switch (rotation) {
12
+ case 90:
13
+ return [flip(y), x];
14
+ case 180:
15
+ return [flip(x), flip(y)];
16
+ case 270:
17
+ return [y, flip(x)];
18
+ default:
19
+ return [x, y];
20
+ }
21
+ }
22
+ /**
23
+ * The view for `target` on a page of `size` (points, `/Rotate` applied) shown at `rotation`, in a
24
+ * `viewport` with `gap` CSS px around pages. A coordinate off the page is clamped onto it.
25
+ */
26
+ export function destinationView(target, size, rotation, viewport, gap) {
27
+ const fraction = (v, of) => v === undefined || of <= 0 ? undefined : Math.min(1, Math.max(0, v / of));
28
+ const at = (x, y) => turn([fraction(x, size.width), fraction(y, size.height)], rotation);
29
+ const shown = rotated(size, rotation);
30
+ const room = { width: Math.max(1, viewport.width - 2 * gap), height: Math.max(1, viewport.height - 2 * gap) };
31
+ const { page, view } = target;
32
+ const go = (zoom, [x, y]) => ({ zoom, page, x, y });
33
+ switch (view.kind) {
34
+ case "at":
35
+ return go(view.zoom === undefined ? undefined : view.zoom * 100, at(view.x, view.y));
36
+ case "fit":
37
+ return go("fit-page", [undefined, undefined]);
38
+ case "fit-width":
39
+ return go("fit-width", at(undefined, view.y));
40
+ case "fit-height":
41
+ return go(percentOfScale(room.height / shown.height), at(view.x, undefined));
42
+ case "fit-rect": {
43
+ const [ax, ay] = at(view.x0, view.y0);
44
+ const [bx, by] = at(view.x1, view.y1);
45
+ const [x0, x1] = [Math.min(ax ?? 0, bx ?? 0), Math.max(ax ?? 0, bx ?? 0)];
46
+ const [y0, y1] = [Math.min(ay ?? 0, by ?? 0), Math.max(ay ?? 0, by ?? 0)];
47
+ // The rectangle's size on screen in points.
48
+ const w = Math.max((x1 - x0) * shown.width, 1);
49
+ const h = Math.max((y1 - y0) * shown.height, 1);
50
+ return go(percentOfScale(Math.min(room.width / w, room.height / h)), [x0, y0]);
51
+ }
52
+ default:
53
+ return go(undefined, [undefined, undefined]);
54
+ }
55
+ }
56
+ //# sourceMappingURL=destination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destination.js","sourceRoot":"","sources":["../../src/zoom/destination.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laminapdf/viewer",
3
- "version": "0.2.0-alpha.2",
3
+ "version": "0.2.0-alpha.4",
4
4
  "description": "The web reader's framework-free viewer core (ADR 0009). Part 1 (C3a): one document worker per document, hosting @laminapdf/sdk and a RenderBackend, behind a typed RPC that extends @laminapdf/sdk/worker with priorities, coalescing, cancellation, timeouts and restart.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "homepage": "https://laminapdf.com",
@@ -31,10 +31,10 @@
31
31
  "./package.json": "./package.json"
32
32
  },
33
33
  "dependencies": {
34
- "@laminapdf/sdk": "0.2.0-alpha.2",
35
- "@laminapdf/render-hayro": "0.2.0-alpha.2",
36
- "@laminapdf/render-pdfium": "0.2.0-alpha.2",
37
- "@laminapdf/render": "0.2.0-alpha.2"
34
+ "@laminapdf/render": "0.2.0-alpha.4",
35
+ "@laminapdf/sdk": "0.2.0-alpha.4",
36
+ "@laminapdf/render-hayro": "0.2.0-alpha.4",
37
+ "@laminapdf/render-pdfium": "0.2.0-alpha.4"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@embedpdf/pdfium": "2.15.1",
@@ -52,6 +52,7 @@
52
52
  "scripts": {
53
53
  "build:wasm": "pnpm --filter @laminapdf/render --filter @laminapdf/render-pdfium run build && pnpm --filter @laminapdf/render-hayro run build:wasm && tsc -p tsconfig.build.json",
54
54
  "typecheck:wasm": "pnpm --filter @laminapdf/render --filter @laminapdf/render-pdfium run build && pnpm --filter @laminapdf/render-hayro run build:wasm && tsc -p tsconfig.build.json && tsc --noEmit -p tsconfig.json",
55
+ "perf": "node perf/run.ts",
55
56
  "test:wasm": "pnpm --filter @laminapdf/render --filter @laminapdf/render-pdfium run build && pnpm --filter @laminapdf/render-hayro run build:wasm && tsc -p tsconfig.build.json && tsc --noEmit -p tsconfig.json && vitest run -c vitest.node.config.ts"
56
57
  }
57
58
  }