@embedpdf/plugin-render 3.0.0-next.6 → 3.0.0-next.7

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.
package/dist/index.d.cts CHANGED
@@ -209,6 +209,45 @@ type RenderAction = {
209
209
  type: 'PAINT_ADVANCED';
210
210
  pon: PageObjectNumber;
211
211
  };
212
+ /**
213
+ * One view's scoped tile surface (see {@link RenderCapability.tilesFor}).
214
+ * Identity (the view) is bound at creation; every call addresses that view's
215
+ * own state for the given page.
216
+ */
217
+ interface ViewTiles {
218
+ /**
219
+ * The tile paint plan for a page under this view's demand. Tiling is a
220
+ * STRATEGY inside this plugin, not a sibling.
221
+ * Memoized: the same object returns until the demand, an epoch, or a
222
+ * tile resolution actually changes it, so layers can subscribe with
223
+ * plain `Object.is`. Calling it schedules the want-set fetches (visible
224
+ * first, center-out, prefetch ring after) — idempotent, store-deduped.
225
+ * Engagement is pure arithmetic against what the base will ACTUALLY
226
+ * supply (the same `baseAsk` the base layer sizes with): tiles fire when
227
+ * demand exceeds the budget/ladder cap × engageAt — on every engine.
228
+ * A thumbnail-sized demand never engages.
229
+ */
230
+ plan(pon: PageObjectNumber, demand: PageViewDemand, opts?: {
231
+ includeAnnotations?: boolean;
232
+ }): TilePaintPlan;
233
+ /**
234
+ * The painter's report: the image for this plan key had a presentation
235
+ * opportunity. Retained coarser generations covered by painted want-set
236
+ * tiles release on this signal — never on fetch completion or image load,
237
+ * which could drop the backdrop before replacement pixels are presented.
238
+ */
239
+ painted(pon: PageObjectNumber, key: string): void;
240
+ /**
241
+ * The inverse report: this plan key's <img> left the DOM, so its pixels
242
+ * are no longer compositable. Painted is a statement about the SCREEN and
243
+ * must follow the DOM — a remounting tile re-decodes, and until it
244
+ * reports painted again, retention may not count it as coverage.
245
+ */
246
+ unpainted(pon: PageObjectNumber, key: string): void;
247
+ /** This view unmounted its tile plane for the page: abort in-flight tile
248
+ * fetches, drop ITS bookkeeping (resolved bytes stay cached). */
249
+ release(pon: PageObjectNumber): void;
250
+ }
212
251
  interface RenderCapability {
213
252
  /**
214
253
  * Render a page (by its durable pon) to an ENCODED image. Abortable. Encoded
@@ -247,37 +286,16 @@ interface RenderCapability {
247
286
  /** The document's advertised policy (sugar over `DocumentMeta.renderPolicy`). */
248
287
  renderPolicy(): EngineRenderPolicy;
249
288
  /**
250
- * The tile paint plan for a page under a host-supplied demand. Tiling is a
251
- * STRATEGY inside this plugin, not a sibling.
252
- * Memoized: the same object returns until the demand, an epoch, or a
253
- * tile resolution actually changes it, so layers can subscribe with
254
- * plain `Object.is`. Calling it schedules the want-set fetches (visible
255
- * first, center-out, prefetch ring after) — idempotent, store-deduped.
256
- * Engagement is pure arithmetic against what the base will ACTUALLY
257
- * supply (the same `baseAsk` the base layer sizes with): tiles fire when
258
- * demand exceeds the budget/ladder cap × engageAt — on every engine.
259
- * A thumbnail-sized demand never engages.
260
- */
261
- tilePlan(pon: PageObjectNumber, demand: PageViewDemand, opts?: {
262
- includeAnnotations?: boolean;
263
- }): TilePaintPlan;
264
- /**
265
- * The painter's report: the image for this plan key had a presentation
266
- * opportunity. Retained coarser generations covered by painted want-set
267
- * tiles release on this signal — never on fetch completion or image load,
268
- * which could drop the backdrop before replacement pixels are presented.
269
- */
270
- tilePainted(pon: PageObjectNumber, key: string): void;
271
- /**
272
- * The inverse report: this plan key's <img> left the DOM, so its pixels
273
- * are no longer compositable. Painted is a statement about the SCREEN and
274
- * must follow the DOM — a remounting tile re-decodes, and until it
275
- * reports painted again, retention may not count it as coverage.
289
+ * This view's tile surface — the ONE tile entry point. `view` is the
290
+ * consuming view's identity (`PageContextValue.view`: a stage lens id, or
291
+ * a PageView instance id). Tile state is kept PER VIEW × PAGE, so two
292
+ * views showing the same page plan independently — a thumbnail rail's
293
+ * never-engaging demand cannot disturb the main view's tiles. Binding the
294
+ * identity ONCE makes it unforgettable and unmixable: the handle's four
295
+ * calls can never disagree about whose state they address. Stable per
296
+ * view — safe as a hook/effect dependency.
276
297
  */
277
- tileUnpainted(pon: PageObjectNumber, key: string): void;
278
- /** A lens unmounted its tile plane: abort in-flight tile fetches and drop
279
- * the page's tile bookkeeping (resolved bytes stay cached). */
280
- releaseTiles(pon: PageObjectNumber): void;
298
+ tilesFor(view: string): ViewTiles;
281
299
  /**
282
300
  * Version of the raster the given options would produce. Key a long-lived
283
301
  * render on it: when it bumps, refetch. Base renders version on content
package/dist/index.d.ts CHANGED
@@ -209,6 +209,45 @@ type RenderAction = {
209
209
  type: 'PAINT_ADVANCED';
210
210
  pon: PageObjectNumber;
211
211
  };
212
+ /**
213
+ * One view's scoped tile surface (see {@link RenderCapability.tilesFor}).
214
+ * Identity (the view) is bound at creation; every call addresses that view's
215
+ * own state for the given page.
216
+ */
217
+ interface ViewTiles {
218
+ /**
219
+ * The tile paint plan for a page under this view's demand. Tiling is a
220
+ * STRATEGY inside this plugin, not a sibling.
221
+ * Memoized: the same object returns until the demand, an epoch, or a
222
+ * tile resolution actually changes it, so layers can subscribe with
223
+ * plain `Object.is`. Calling it schedules the want-set fetches (visible
224
+ * first, center-out, prefetch ring after) — idempotent, store-deduped.
225
+ * Engagement is pure arithmetic against what the base will ACTUALLY
226
+ * supply (the same `baseAsk` the base layer sizes with): tiles fire when
227
+ * demand exceeds the budget/ladder cap × engageAt — on every engine.
228
+ * A thumbnail-sized demand never engages.
229
+ */
230
+ plan(pon: PageObjectNumber, demand: PageViewDemand, opts?: {
231
+ includeAnnotations?: boolean;
232
+ }): TilePaintPlan;
233
+ /**
234
+ * The painter's report: the image for this plan key had a presentation
235
+ * opportunity. Retained coarser generations covered by painted want-set
236
+ * tiles release on this signal — never on fetch completion or image load,
237
+ * which could drop the backdrop before replacement pixels are presented.
238
+ */
239
+ painted(pon: PageObjectNumber, key: string): void;
240
+ /**
241
+ * The inverse report: this plan key's <img> left the DOM, so its pixels
242
+ * are no longer compositable. Painted is a statement about the SCREEN and
243
+ * must follow the DOM — a remounting tile re-decodes, and until it
244
+ * reports painted again, retention may not count it as coverage.
245
+ */
246
+ unpainted(pon: PageObjectNumber, key: string): void;
247
+ /** This view unmounted its tile plane for the page: abort in-flight tile
248
+ * fetches, drop ITS bookkeeping (resolved bytes stay cached). */
249
+ release(pon: PageObjectNumber): void;
250
+ }
212
251
  interface RenderCapability {
213
252
  /**
214
253
  * Render a page (by its durable pon) to an ENCODED image. Abortable. Encoded
@@ -247,37 +286,16 @@ interface RenderCapability {
247
286
  /** The document's advertised policy (sugar over `DocumentMeta.renderPolicy`). */
248
287
  renderPolicy(): EngineRenderPolicy;
249
288
  /**
250
- * The tile paint plan for a page under a host-supplied demand. Tiling is a
251
- * STRATEGY inside this plugin, not a sibling.
252
- * Memoized: the same object returns until the demand, an epoch, or a
253
- * tile resolution actually changes it, so layers can subscribe with
254
- * plain `Object.is`. Calling it schedules the want-set fetches (visible
255
- * first, center-out, prefetch ring after) — idempotent, store-deduped.
256
- * Engagement is pure arithmetic against what the base will ACTUALLY
257
- * supply (the same `baseAsk` the base layer sizes with): tiles fire when
258
- * demand exceeds the budget/ladder cap × engageAt — on every engine.
259
- * A thumbnail-sized demand never engages.
260
- */
261
- tilePlan(pon: PageObjectNumber, demand: PageViewDemand, opts?: {
262
- includeAnnotations?: boolean;
263
- }): TilePaintPlan;
264
- /**
265
- * The painter's report: the image for this plan key had a presentation
266
- * opportunity. Retained coarser generations covered by painted want-set
267
- * tiles release on this signal — never on fetch completion or image load,
268
- * which could drop the backdrop before replacement pixels are presented.
269
- */
270
- tilePainted(pon: PageObjectNumber, key: string): void;
271
- /**
272
- * The inverse report: this plan key's <img> left the DOM, so its pixels
273
- * are no longer compositable. Painted is a statement about the SCREEN and
274
- * must follow the DOM — a remounting tile re-decodes, and until it
275
- * reports painted again, retention may not count it as coverage.
289
+ * This view's tile surface — the ONE tile entry point. `view` is the
290
+ * consuming view's identity (`PageContextValue.view`: a stage lens id, or
291
+ * a PageView instance id). Tile state is kept PER VIEW × PAGE, so two
292
+ * views showing the same page plan independently — a thumbnail rail's
293
+ * never-engaging demand cannot disturb the main view's tiles. Binding the
294
+ * identity ONCE makes it unforgettable and unmixable: the handle's four
295
+ * calls can never disagree about whose state they address. Stable per
296
+ * view — safe as a hook/effect dependency.
276
297
  */
277
- tileUnpainted(pon: PageObjectNumber, key: string): void;
278
- /** A lens unmounted its tile plane: abort in-flight tile fetches and drop
279
- * the page's tile bookkeeping (resolved bytes stay cached). */
280
- releaseTiles(pon: PageObjectNumber): void;
298
+ tilesFor(view: string): ViewTiles;
281
299
  /**
282
300
  * Version of the raster the given options would produce. Key a long-lived
283
301
  * render on it: when it bumps, refetch. Base renders version on content
package/dist/index.js CHANGED
@@ -373,6 +373,8 @@ function snapToPyramid(scales, needed) {
373
373
  * is idempotent (the store singleflights); resolution handlers dispatch
374
374
  * the wake-up (`onAdvance`) that makes subscribed layers recompute.
375
375
  */
376
+ /** One state entry per VIEW-of-page (see the class doc). */
377
+ const stateKey = (view, pon) => `${view}\u0000${pon}`;
376
378
  /** Backpressure: raw rasters in flight at once (render + encode transit). */
377
379
  const MAX_IN_FLIGHT = 8;
378
380
  /** Stage-less (no visibleRect) demand is capped to this many whole-page tiles. */
@@ -393,14 +395,14 @@ var TileManager = class {
393
395
  };
394
396
  return this.strategyMemo.strategy;
395
397
  }
396
- plan(pon, demand, includeAnnotations) {
398
+ plan(view, pon, demand, includeAnnotations) {
397
399
  const { options } = this.deps;
398
400
  if (!options.tiles.enabled) return EMPTY_TILE_PLAN;
399
401
  const strategy = this.strategy();
400
402
  const page = this.deps.getPageSize(pon);
401
403
  if (!page) return EMPTY_TILE_PLAN;
402
404
  const epoch = this.deps.getEpoch(pon, includeAnnotations);
403
- const state = this.pageState(pon);
405
+ const state = this.pageState(pon, view);
404
406
  if (state.epoch !== epoch) {
405
407
  this.abortAll(state);
406
408
  state.entries.clear();
@@ -511,8 +513,8 @@ var TileManager = class {
511
513
  return plan;
512
514
  }
513
515
  /** The layer's painted report: this key's pixels had a presentation opportunity. */
514
- sourcePainted(pon, key) {
515
- const state = this.pages.get(pon);
516
+ sourcePainted(view, pon, key) {
517
+ const state = this.pages.get(stateKey(view, pon));
516
518
  const entry = state?.entries.get(key);
517
519
  if (!state || !entry || entry.painted) return;
518
520
  entry.painted = true;
@@ -530,20 +532,20 @@ var TileManager = class {
530
532
  * retained coarse coverage over a region that momentarily has no sharp
531
533
  * pixels. Painted is a statement about the SCREEN, so it follows the DOM.
532
534
  */
533
- sourceUnpainted(pon, key) {
534
- const entry = this.pages.get(pon)?.entries.get(key);
535
+ sourceUnpainted(view, pon, key) {
536
+ const entry = this.pages.get(stateKey(view, pon))?.entries.get(key);
535
537
  if (entry) entry.painted = false;
536
538
  }
537
539
  /** A lens unmounted its tile plane: stop fetching, drop bookkeeping.
538
540
  * Resolved bytes stay in the RasterStore for a re-mount. */
539
- releasePage(pon) {
540
- const state = this.pages.get(pon);
541
+ releasePage(view, pon) {
542
+ const state = this.pages.get(stateKey(view, pon));
541
543
  if (!state) return;
542
544
  this.abortAll(state);
543
- this.pages.delete(pon);
545
+ this.pages.delete(stateKey(view, pon));
544
546
  }
545
- pageState(pon) {
546
- let state = this.pages.get(pon);
547
+ pageState(pon, view) {
548
+ let state = this.pages.get(stateKey(view, pon));
547
549
  if (!state) {
548
550
  state = {
549
551
  epoch: -1,
@@ -557,7 +559,7 @@ var TileManager = class {
557
559
  pendingLevel: null,
558
560
  lastVisible: null
559
561
  };
560
- this.pages.set(pon, state);
562
+ this.pages.set(stateKey(view, pon), state);
561
563
  }
562
564
  return state;
563
565
  }
@@ -702,9 +704,9 @@ var TileManager = class {
702
704
  return released;
703
705
  }
704
706
  /** Test/diagnostic introspection: bookkeeping size for one page. */
705
- stats(pon) {
707
+ stats(view, pon) {
706
708
  return {
707
- entries: this.pages.get(pon)?.entries.size ?? 0,
709
+ entries: this.pages.get(stateKey(view, pon))?.entries.size ?? 0,
708
710
  inFlight: this.inFlight
709
711
  };
710
712
  }
@@ -823,6 +825,7 @@ function createRenderCapability(ctx, options = {}) {
823
825
  });
824
826
  });
825
827
  };
828
+ const viewTiles = /* @__PURE__ */ new Map();
826
829
  const tiles = new TileManager({
827
830
  store,
828
831
  options: resolved,
@@ -885,17 +888,18 @@ function createRenderCapability(ctx, options = {}) {
885
888
  };
886
889
  },
887
890
  renderPolicy: policy,
888
- tilePlan(pon, demand, opts) {
889
- return tiles.plan(pon, demand, opts?.includeAnnotations ?? true);
890
- },
891
- tilePainted(pon, key) {
892
- tiles.sourcePainted(pon, key);
893
- },
894
- tileUnpainted(pon, key) {
895
- tiles.sourceUnpainted(pon, key);
896
- },
897
- releaseTiles(pon) {
898
- tiles.releasePage(pon);
891
+ tilesFor(view) {
892
+ let handle = viewTiles.get(view);
893
+ if (!handle) {
894
+ handle = {
895
+ plan: (pon, demand, opts) => tiles.plan(view, pon, demand, opts?.includeAnnotations ?? true),
896
+ painted: (pon, key) => tiles.sourcePainted(view, pon, key),
897
+ unpainted: (pon, key) => tiles.sourceUnpainted(view, pon, key),
898
+ release: (pon) => tiles.releasePage(view, pon)
899
+ };
900
+ viewTiles.set(view, handle);
901
+ }
902
+ return handle;
899
903
  },
900
904
  renderEpoch(pon, includeAnnotations = true) {
901
905
  return epochOf(pon, includeAnnotations);