web-doc 0.8.0 → 0.10.0

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 (38) hide show
  1. package/THIRD_PARTY_NOTICES.md +14 -0
  2. package/dist/adapters/office.js +2 -1
  3. package/dist/contracts.d.ts +9 -0
  4. package/dist/edit/ai/tools.js +3 -1
  5. package/dist/edit/docx/elements.js +19 -1
  6. package/dist/edit/docx/types.d.ts +8 -0
  7. package/dist/edit/pdf/engine/cff.d.ts +28 -0
  8. package/dist/edit/pdf/engine/cff.js +416 -0
  9. package/dist/edit/pdf/engine/document.d.ts +3 -1
  10. package/dist/edit/pdf/engine/document.js +69 -4
  11. package/dist/edit/pdf/engine/elements.d.ts +13 -0
  12. package/dist/edit/pdf/engine/elements.js +12 -1
  13. package/dist/edit/pdf/engine/existing-text.js +6 -4
  14. package/dist/edit/pdf/engine/fonts.js +13 -10
  15. package/dist/edit/pdf/engine/glyph-names.d.ts +2 -0
  16. package/dist/edit/pdf/engine/glyph-names.js +163 -0
  17. package/dist/edit/pdf/engine/handler.js +2 -0
  18. package/dist/edit/pdf/engine/opentype.d.ts +14 -0
  19. package/dist/edit/pdf/engine/opentype.js +317 -0
  20. package/dist/edit/pdf/engine/pages.js +9 -1
  21. package/dist/edit/pdf/engine/text-font.d.ts +4 -0
  22. package/dist/edit/pdf/engine/text-font.js +81 -0
  23. package/dist/edit/pdf/provider.d.ts +3 -1
  24. package/dist/edit/pdf/provider.js +3 -0
  25. package/dist/edit/pdf/schemas.js +4 -1
  26. package/dist/edit/pdf/session.d.ts +2 -1
  27. package/dist/edit/pdf/session.js +3 -0
  28. package/dist/edit/pdf/types.d.ts +55 -3
  29. package/dist/edit/pptx/session.d.ts +7 -2
  30. package/dist/edit/pptx/session.js +41 -3
  31. package/dist/fonts/THIRD_PARTY_NOTICES.md +6 -3
  32. package/dist/fonts/manifest.json +4 -4
  33. package/dist/fonts/noto-sans-latin-cyrillic.ttf +0 -0
  34. package/dist/viewport.js +83 -20
  35. package/dist/worker-protocol.d.ts +1 -1
  36. package/dist/workers/ooxml-edit-worker.js +15 -1
  37. package/dist/workers/pdf-edit-worker.js +1176 -197
  38. package/package.json +1 -1
@@ -1,8 +1,9 @@
1
1
  import { ViewerError } from "../../../errors.js";
2
2
  import { invalidOperationError, parseReference } from "../../operations.js";
3
3
  import { layoutOf, layoutsOf, positionIn, rectsOf, } from "./layout.js";
4
- import { markIsFresh, readMark, scanPage, } from "./elements.js";
4
+ import { markIsFresh, OBJECT_TEXT, readMark, scanPage, } from "./elements.js";
5
5
  import { FontLibrary, TextMeasurer } from "./fonts.js";
6
+ import { textFaceOf } from "./text-font.js";
6
7
  import { fontRequestsOf } from "./text-box.js";
7
8
  import { issueCollector, } from "./operations.js";
8
9
  import { insertTextBox } from "./text-box.js";
@@ -123,6 +124,8 @@ export class PdfEditDocument {
123
124
  #measurer;
124
125
  #pages;
125
126
  #batches = 0;
127
+ /** Browser faces of the document's fonts, by font program; see `textFont`. */
128
+ #faces = new Map();
126
129
  constructor(pdfium, original, fonts = new FontLibrary(async () => {
127
130
  throw new Error("No font source is configured");
128
131
  }), limits = defaultResourceLimits, assets = new AssetStore(), compact = compactPdf) {
@@ -402,6 +405,23 @@ export class PdfEditDocument {
402
405
  return element ? layoutOf(this.#pdfium, scan, element) : undefined;
403
406
  });
404
407
  }
408
+ /** The browser face of the font a text or text box element is drawn in, see `TextFont`. */
409
+ textFont(elementId) {
410
+ const location = this.#locate(elementId);
411
+ const element = location && this.getElement(elementId);
412
+ if (!element || (element.kind !== "text" && element.kind !== "textBox"))
413
+ return undefined;
414
+ const { lib } = this.#pdfium;
415
+ return this.#withPage(location.pageIndex, (page) => {
416
+ // A text box's lines share their font; its first line answers.
417
+ const object = location.indexes
418
+ .map((index) => lib.FPDFPage_GetObject(page, index))
419
+ .find((entry) => lib.FPDFPageObj_GetType(entry) === OBJECT_TEXT);
420
+ return object === undefined
421
+ ? undefined
422
+ : { elementId, ...textFaceOf(this.#pdfium, object, this.#faces) };
423
+ });
424
+ }
405
425
  /** The layouts of every text element on a page, with the page's displayed size. */
406
426
  pageLayout(pageIndex) {
407
427
  if (pageIndex < 0 || pageIndex >= this.#pages.length)
@@ -535,8 +555,11 @@ export class PdfEditDocument {
535
555
  },
536
556
  // Ids name the state the batch leads to, the operation and the item,
537
557
  // so replaying the history reproduces them and an undone id is never
538
- // handed out again.
539
- newId: (pageIndex, suffix = "") => `${this.#pages[pageIndex].key}:n${stateId}.${operationIndex}.${created++}${suffix}`,
558
+ // handed out again. A file saved by an earlier session carries the ids
559
+ // that session numbered from 1 as well, so one already on the page
560
+ // gets the first free `~n` instead (ACTION-886); the saved objects are
561
+ // part of the base, so a replay meets them and picks the same id.
562
+ newId: (pageIndex, suffix = "") => `${this.#unusedId(pageIndex, `${this.#pages[pageIndex].key}:n${stateId}.${operationIndex}.${created++}`)}${suffix}`,
540
563
  withPage: (pageIndex, use) => this.#writePage(pageIndex, use),
541
564
  appendObjects: (pageIndex, records) => {
542
565
  const page = this.#pages[pageIndex];
@@ -686,10 +709,52 @@ export class PdfEditDocument {
686
709
  }
687
710
  }
688
711
  record.objects = objects.map((object, index) => object.mark && stale.has(object.id)
689
- ? { id: `${record.key}:o${index}`, type: object.type }
712
+ ? {
713
+ id: `${record.key}:o${index}`,
714
+ type: object.type,
715
+ staleMarkId: object.id,
716
+ }
690
717
  : object);
691
718
  return record.objects;
692
719
  }
720
+ /**
721
+ * `id`, or its first free `~n` when an object saved by an earlier session
722
+ * has it already. Only ids a session numbered (`<key>:n…`) can collide, so
723
+ * only those are gathered; the objects are read without the page's text.
724
+ */
725
+ #unusedId(pageIndex, id) {
726
+ const record = this.#pages[pageIndex];
727
+ const objects = record.objects ?? this.#loadObjects(pageIndex);
728
+ const numbered = `${record.key}:n`;
729
+ const taken = new Set();
730
+ for (const object of objects) {
731
+ if (object.id.startsWith(numbered))
732
+ taken.add(object.id);
733
+ if (object.staleMarkId?.startsWith(numbered))
734
+ taken.add(object.staleMarkId);
735
+ }
736
+ if (!taken.has(id))
737
+ return id;
738
+ let suffix = 1;
739
+ while (taken.has(`${id}~${suffix}`))
740
+ suffix += 1;
741
+ return `${id}~${suffix}`;
742
+ }
743
+ /** A page's objects, loading the page alone when they are not known yet. */
744
+ #loadObjects(pageIndex) {
745
+ const { lib } = this.#pdfium;
746
+ const page = lib.FPDF_LoadPage(this.#document.handle, pageIndex);
747
+ if (!page)
748
+ throw new ViewerError("render-failed", "PDFium could not load the page", {
749
+ details: { pageIndex },
750
+ });
751
+ try {
752
+ return this.#objectsOf(pageIndex, page);
753
+ }
754
+ finally {
755
+ lib.FPDF_ClosePage(page);
756
+ }
757
+ }
693
758
  /** Marks from other sessions keep their id only if it cannot collide with ours. */
694
759
  #ownMark(mark, pageKey) {
695
760
  return mark.id.startsWith(`${pageKey}:`)
@@ -21,6 +21,12 @@ export interface ObjectRecord {
21
21
  readonly id: string;
22
22
  readonly type: number;
23
23
  readonly mark?: MarkParams;
24
+ /**
25
+ * The id a mark the file still carries names, on an object listed as plain
26
+ * because the mark failed its check: a new id must not take it, or saving
27
+ * would join the new object to this one.
28
+ */
29
+ readonly staleMarkId?: string;
24
30
  }
25
31
  /**
26
32
  * Reads the objects of a loaded page in drawing order and turns them into
@@ -41,5 +47,12 @@ export declare function readMark(pdfium: Pdfium, object: number): MarkParams | u
41
47
  */
42
48
  export declare function markIsFresh(pdfium: Pdfium, page: number, textPage: number, geometry: PageGeometry, mark: MarkParams, indexes: readonly number[]): boolean;
43
49
  export declare function objectBounds(pdfium: Pdfium, object: number, geometry: PageGeometry): PageRect | undefined;
50
+ /**
51
+ * How much a text object's matrix scales its glyphs: the length of its
52
+ * vertical axis. Producers often write `1 Tf` and carry the size in the
53
+ * matrix, so the point size the text shows is its font size times this; a
54
+ * turn or a horizontal squeeze leaves it alone.
55
+ */
56
+ export declare function textScale(matrix: readonly number[] | undefined): number;
44
57
  export declare function textStyle(pdfium: Pdfium, object: number): PdfTextStyle;
45
58
  export declare function hex(rgba: readonly number[]): string;
@@ -232,6 +232,16 @@ const TABLE_OPERATIONS = Object.freeze([
232
232
  function textOf(pdfium, object, textPage) {
233
233
  return pdfium.readWideString((buffer, bytes) => pdfium.lib.FPDFTextObj_GetText(object, textPage, buffer, bytes));
234
234
  }
235
+ /**
236
+ * How much a text object's matrix scales its glyphs: the length of its
237
+ * vertical axis. Producers often write `1 Tf` and carry the size in the
238
+ * matrix, so the point size the text shows is its font size times this; a
239
+ * turn or a horizontal squeeze leaves it alone.
240
+ */
241
+ export function textScale(matrix) {
242
+ const scale = matrix ? Math.hypot(matrix[2], matrix[3]) : 1;
243
+ return Number.isFinite(scale) && scale > 0 ? scale : 1;
244
+ }
235
245
  export function textStyle(pdfium, object) {
236
246
  const { lib } = pdfium;
237
247
  const font = lib.FPDFTextObj_GetFont(object);
@@ -245,9 +255,10 @@ export function textStyle(pdfium, object) {
245
255
  const flags = lib.FPDFFont_GetFlags(font);
246
256
  const weight = lib.FPDFFont_GetWeight(font);
247
257
  const size = pdfium.readNumbers(1, "float", ([pointer]) => lib.FPDFTextObj_GetFontSize(object, pointer))?.[0] ?? 0;
258
+ const matrix = pdfium.readNumbers(6, "float", ([pointer]) => lib.FPDFPageObj_GetMatrix(object, pointer));
248
259
  return {
249
260
  fontFamily: family,
250
- fontSize: round(size),
261
+ fontSize: round(size * textScale(matrix)),
251
262
  bold: weight >= 600 ||
252
263
  (flags & FLAG_FORCE_BOLD) !== 0 ||
253
264
  /bold|black|heavy/i.test(baseName),
@@ -1,4 +1,4 @@
1
- import { objectBounds, OBJECT_TEXT } from "./elements.js";
1
+ import { objectBounds, OBJECT_TEXT, textScale } from "./elements.js";
2
2
  import { firstNonWinAnsi, isStandardFamily, parseCmap, } from "./fonts.js";
3
3
  import { pageToUser } from "./geometry.js";
4
4
  import { parseColor, setText, textBoxReplaceText, textBoxSetTextStyle, textBoxTarget, } from "./text-box.js";
@@ -255,7 +255,7 @@ function splitAround(context, target, before, middle, after) {
255
255
  const old = lib.FPDFPage_GetObject(page, index);
256
256
  const oldFont = lib.FPDFTextObj_GetFont(old);
257
257
  const matrix = pdfium.readNumbers(6, "float", ([pointer]) => lib.FPDFPageObj_GetMatrix(old, pointer)) ?? [1, 0, 0, 1, 0, 0];
258
- const size = pdfium.readNumbers(1, "float", ([pointer]) => lib.FPDFTextObj_GetFontSize(old, pointer))?.[0] ?? style.fontSize;
258
+ const size = pdfium.readNumbers(1, "float", ([pointer]) => lib.FPDFTextObj_GetFontSize(old, pointer))?.[0] ?? style.fontSize / textScale(matrix);
259
259
  const [a, b, c, d, e, f] = matrix;
260
260
  const [r, g, bl] = parseColor(style.color);
261
261
  const parts = [
@@ -349,7 +349,7 @@ function replaceWithFallback(context, target, text) {
349
349
  context.withPage(location.pageIndex, (page) => {
350
350
  const old = lib.FPDFPage_GetObject(page, index);
351
351
  const matrix = pdfium.readNumbers(6, "float", ([pointer]) => lib.FPDFPageObj_GetMatrix(old, pointer)) ?? [1, 0, 0, 1, 0, 0];
352
- const size = pdfium.readNumbers(1, "float", ([pointer]) => lib.FPDFTextObj_GetFontSize(old, pointer))?.[0] ?? style.fontSize;
352
+ const size = pdfium.readNumbers(1, "float", ([pointer]) => lib.FPDFTextObj_GetFontSize(old, pointer))?.[0] ?? style.fontSize / textScale(matrix);
353
353
  const object = lib.FPDFPageObj_CreateTextObj(context.document, font.handle, size);
354
354
  setText(pdfium, object, text);
355
355
  const [r, g, b] = parseColor(style.color);
@@ -399,7 +399,9 @@ function resize(context, target, fontSize) {
399
399
  }
400
400
  const matrix = pdfium.readNumbers(6, "float", ([pointer]) => lib.FPDFPageObj_GetMatrix(old, pointer)) ?? [1, 0, 0, 1, 0, 0];
401
401
  const color = pdfium.readNumbers(4, "i32", ([r, g, b, a]) => lib.FPDFPageObj_GetFillColor(old, r, g, b, a)) ?? [0, 0, 0, 255];
402
- const object = lib.FPDFPageObj_CreateTextObj(context.document, lib.FPDFTextObj_GetFont(old), fontSize);
402
+ // The size is the one the text shows: the old matrix, applied below,
403
+ // scales it again, so the font gets the size undone by that scale.
404
+ const object = lib.FPDFPageObj_CreateTextObj(context.document, lib.FPDFTextObj_GetFont(old), fontSize / textScale(matrix));
403
405
  setText(pdfium, object, text);
404
406
  lib.FPDFPageObj_SetFillColor(object, color[0], color[1], color[2], color[3]);
405
407
  const [a, b, c, d, e, f] = matrix;
@@ -110,7 +110,13 @@ export class FontLibrary {
110
110
  return undefined;
111
111
  if (this.#fallback && this.#covers(this.#fallback, request.text))
112
112
  return undefined;
113
- const bad = firstNonWinAnsi(request.text) ?? firstUncovered(request.text, this);
113
+ // Name the character that actually stops the text: the first one the
114
+ // fallback lacks when it was tried, else the first the standard fonts
115
+ // cannot encode. Naming the first Cyrillic letter for a dash the
116
+ // fallback lacked sent people after the wrong character (ACTION-879).
117
+ const bad = this.#fallback
118
+ ? this.#firstMissing(this.#fallback, request.text)
119
+ : firstNonWinAnsi(request.text);
114
120
  return {
115
121
  path: "/text",
116
122
  code: "font-unavailable",
@@ -175,6 +181,10 @@ export class FontLibrary {
175
181
  return candidates.sort((a, b) => score(b.font) - score(a.font))[0];
176
182
  }
177
183
  #covers(bytes, text) {
184
+ return this.#firstMissing(bytes, text) === undefined;
185
+ }
186
+ /** The first character of `text` the font has no glyph for; layout handles line breaks and spaces. */
187
+ #firstMissing(bytes, text) {
178
188
  let coverage = this.#coverage.get(bytes);
179
189
  if (!coverage) {
180
190
  coverage = parseCmap(bytes);
@@ -185,9 +195,9 @@ export class FontLibrary {
185
195
  if (code === 0x0a || code === 0x20)
186
196
  continue;
187
197
  if (!coverage.has(code))
188
- return false;
198
+ return character;
189
199
  }
190
- return true;
200
+ return undefined;
191
201
  }
192
202
  #load(pdfium, document, bytes) {
193
203
  let handles = this.#handles.get(document);
@@ -242,13 +252,6 @@ function isBold(font) {
242
252
  function isItalic(font) {
243
253
  return font.style !== "normal";
244
254
  }
245
- function firstUncovered(text, library) {
246
- void library;
247
- for (const character of text)
248
- if (character !== "\n" && character !== " ")
249
- return character;
250
- return undefined;
251
- }
252
255
  /** The code points a TrueType font maps to glyphs, from its cmap table. */
253
256
  /**
254
257
  * Whether glyphs of a TrueType font have outline data: a subset font can keep
@@ -0,0 +1,2 @@
1
+ /** Code points by glyph name. */
2
+ export declare const GLYPH_UNICODE: ReadonlyMap<string, number>;
@@ -0,0 +1,163 @@
1
+ /*
2
+ * Glyph names and the code points they stand for: the Adobe Glyph List For
3
+ * New Fonts 1.7 (aglfn.txt), and from the Adobe Glyph List 2.0
4
+ * (glyphlist.txt) the ligatures, superior figures and no-break space that
5
+ * font subsets commonly name, from https://github.com/adobe-type-tools/agl-aglfn.
6
+ * Each is listed as a name and its code point in hexadecimal.
7
+ *
8
+ * Copyright 2002-2019 Adobe (http://www.adobe.com/).
9
+ *
10
+ * Redistribution and use in source and binary forms, with or
11
+ * without modification, are permitted provided that the
12
+ * following conditions are met:
13
+ *
14
+ * Redistributions of source code must retain the above
15
+ * copyright notice, this list of conditions and the following
16
+ * disclaimer.
17
+ *
18
+ * Redistributions in binary form must reproduce the above
19
+ * copyright notice, this list of conditions and the following
20
+ * disclaimer in the documentation and/or other materials
21
+ * provided with the distribution.
22
+ *
23
+ * Neither the name of Adobe nor the names of its contributors
24
+ * may be used to endorse or promote products derived from this
25
+ * software without specific prior written permission.
26
+ *
27
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
28
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
29
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
34
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
38
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
+ */
41
+ const AGLFN = `
42
+ A 0041 AE 00C6 AEacute 01FC Aacute 00C1 Abreve 0102 Acircumflex 00C2
43
+ Adieresis 00C4 Agrave 00C0 Alpha 0391 Alphatonos 0386 Amacron 0100
44
+ Aogonek 0104 Aring 00C5 Aringacute 01FA Atilde 00C3 B 0042 Beta 0392 C 0043
45
+ Cacute 0106 Ccaron 010C Ccedilla 00C7 Ccircumflex 0108 Cdotaccent 010A
46
+ Chi 03A7 D 0044 Dcaron 010E Dcroat 0110 Delta 2206 E 0045 Eacute 00C9
47
+ Ebreve 0114 Ecaron 011A Ecircumflex 00CA Edieresis 00CB Edotaccent 0116
48
+ Egrave 00C8 Emacron 0112 Eng 014A Eogonek 0118 Epsilon 0395
49
+ Epsilontonos 0388 Eta 0397 Etatonos 0389 Eth 00D0 Euro 20AC F 0046 G 0047
50
+ Gamma 0393 Gbreve 011E Gcaron 01E6 Gcircumflex 011C Gdotaccent 0120 H 0048
51
+ H18533 25CF H18543 25AA H18551 25AB H22073 25A1 Hbar 0126 Hcircumflex 0124
52
+ I 0049 IJ 0132 Iacute 00CD Ibreve 012C Icircumflex 00CE Idieresis 00CF
53
+ Idotaccent 0130 Ifraktur 2111 Igrave 00CC Imacron 012A Iogonek 012E
54
+ Iota 0399 Iotadieresis 03AA Iotatonos 038A Itilde 0128 J 004A
55
+ Jcircumflex 0134 K 004B Kappa 039A L 004C Lacute 0139 Lambda 039B
56
+ Lcaron 013D Ldot 013F Lslash 0141 M 004D Mu 039C N 004E Nacute 0143
57
+ Ncaron 0147 Ntilde 00D1 Nu 039D O 004F OE 0152 Oacute 00D3 Obreve 014E
58
+ Ocircumflex 00D4 Odieresis 00D6 Ograve 00D2 Ohorn 01A0 Ohungarumlaut 0150
59
+ Omacron 014C Omega 2126 Omegatonos 038F Omicron 039F Omicrontonos 038C
60
+ Oslash 00D8 Oslashacute 01FE Otilde 00D5 P 0050 Phi 03A6 Pi 03A0 Psi 03A8
61
+ Q 0051 R 0052 Racute 0154 Rcaron 0158 Rfraktur 211C Rho 03A1 S 0053
62
+ SF010000 250C SF020000 2514 SF030000 2510 SF040000 2518 SF050000 253C
63
+ SF060000 252C SF070000 2534 SF080000 251C SF090000 2524 SF100000 2500
64
+ SF110000 2502 SF190000 2561 SF200000 2562 SF210000 2556 SF220000 2555
65
+ SF230000 2563 SF240000 2551 SF250000 2557 SF260000 255D SF270000 255C
66
+ SF280000 255B SF360000 255E SF370000 255F SF380000 255A SF390000 2554
67
+ SF400000 2569 SF410000 2566 SF420000 2560 SF430000 2550 SF440000 256C
68
+ SF450000 2567 SF460000 2568 SF470000 2564 SF480000 2565 SF490000 2559
69
+ SF500000 2558 SF510000 2552 SF520000 2553 SF530000 256B SF540000 256A
70
+ Sacute 015A Scaron 0160 Scedilla 015E Scircumflex 015C Sigma 03A3 T 0054
71
+ Tau 03A4 Tbar 0166 Tcaron 0164 Theta 0398 Thorn 00DE U 0055 Uacute 00DA
72
+ Ubreve 016C Ucircumflex 00DB Udieresis 00DC Ugrave 00D9 Uhorn 01AF
73
+ Uhungarumlaut 0170 Umacron 016A Uogonek 0172 Upsilon 03A5 Upsilon1 03D2
74
+ Upsilondieresis 03AB Upsilontonos 038E Uring 016E Utilde 0168 V 0056 W 0057
75
+ Wacute 1E82 Wcircumflex 0174 Wdieresis 1E84 Wgrave 1E80 X 0058 Xi 039E
76
+ Y 0059 Yacute 00DD Ycircumflex 0176 Ydieresis 0178 Ygrave 1EF2 Z 005A
77
+ Zacute 0179 Zcaron 017D Zdotaccent 017B Zeta 0396 a 0061 aacute 00E1
78
+ abreve 0103 acircumflex 00E2 acute 00B4 acutecomb 0301 adieresis 00E4
79
+ ae 00E6 aeacute 01FD agrave 00E0 aleph 2135 alpha 03B1 alphatonos 03AC
80
+ amacron 0101 ampersand 0026 angle 2220 angleleft 2329 angleright 232A
81
+ anoteleia 0387 aogonek 0105 approxequal 2248 aring 00E5 aringacute 01FB
82
+ arrowboth 2194 arrowdblboth 21D4 arrowdbldown 21D3 arrowdblleft 21D0
83
+ arrowdblright 21D2 arrowdblup 21D1 arrowdown 2193 arrowleft 2190
84
+ arrowright 2192 arrowup 2191 arrowupdn 2195 arrowupdnbse 21A8
85
+ asciicircum 005E asciitilde 007E asterisk 002A asteriskmath 2217 at 0040
86
+ atilde 00E3 b 0062 backslash 005C bar 007C beta 03B2 block 2588
87
+ braceleft 007B braceright 007D bracketleft 005B bracketright 005D breve 02D8
88
+ brokenbar 00A6 bullet 2022 c 0063 cacute 0107 caron 02C7 carriagereturn 21B5
89
+ ccaron 010D ccedilla 00E7 ccircumflex 0109 cdotaccent 010B cedilla 00B8
90
+ cent 00A2 chi 03C7 circle 25CB circlemultiply 2297 circleplus 2295
91
+ circumflex 02C6 club 2663 colon 003A colonmonetary 20A1 comma 002C
92
+ congruent 2245 copyright 00A9 currency 00A4 d 0064 dagger 2020
93
+ daggerdbl 2021 dcaron 010F dcroat 0111 degree 00B0 delta 03B4 diamond 2666
94
+ dieresis 00A8 dieresistonos 0385 divide 00F7 dkshade 2593 dnblock 2584
95
+ dollar 0024 dong 20AB dotaccent 02D9 dotbelowcomb 0323 dotlessi 0131
96
+ dotmath 22C5 e 0065 eacute 00E9 ebreve 0115 ecaron 011B ecircumflex 00EA
97
+ edieresis 00EB edotaccent 0117 egrave 00E8 eight 0038 element 2208
98
+ ellipsis 2026 emacron 0113 emdash 2014 emptyset 2205 endash 2013 eng 014B
99
+ eogonek 0119 epsilon 03B5 epsilontonos 03AD equal 003D equivalence 2261
100
+ estimated 212E eta 03B7 etatonos 03AE eth 00F0 exclam 0021 exclamdbl 203C
101
+ exclamdown 00A1 existential 2203 f 0066 female 2640 figuredash 2012
102
+ filledbox 25A0 filledrect 25AC five 0035 fiveeighths 215D florin 0192
103
+ four 0034 fraction 2044 franc 20A3 g 0067 gamma 03B3 gbreve 011F gcaron 01E7
104
+ gcircumflex 011D gdotaccent 0121 germandbls 00DF gradient 2207 grave 0060
105
+ gravecomb 0300 greater 003E greaterequal 2265 guillemotleft 00AB
106
+ guillemotright 00BB guilsinglleft 2039 guilsinglright 203A h 0068 hbar 0127
107
+ hcircumflex 0125 heart 2665 hookabovecomb 0309 house 2302 hungarumlaut 02DD
108
+ hyphen 002D i 0069 iacute 00ED ibreve 012D icircumflex 00EE idieresis 00EF
109
+ igrave 00EC ij 0133 imacron 012B infinity 221E integral 222B integralbt 2321
110
+ integraltp 2320 intersection 2229 invbullet 25D8 invcircle 25D9
111
+ invsmileface 263B iogonek 012F iota 03B9 iotadieresis 03CA
112
+ iotadieresistonos 0390 iotatonos 03AF itilde 0129 j 006A jcircumflex 0135
113
+ k 006B kappa 03BA kgreenlandic 0138 l 006C lacute 013A lambda 03BB
114
+ lcaron 013E ldot 0140 less 003C lessequal 2264 lfblock 258C lira 20A4
115
+ logicaland 2227 logicalnot 00AC logicalor 2228 longs 017F lozenge 25CA
116
+ lslash 0142 ltshade 2591 m 006D macron 00AF male 2642 minus 2212 minute 2032
117
+ mu 00B5 multiply 00D7 musicalnote 266A musicalnotedbl 266B n 006E
118
+ nacute 0144 napostrophe 0149 ncaron 0148 nine 0039 notelement 2209
119
+ notequal 2260 notsubset 2284 ntilde 00F1 nu 03BD numbersign 0023 o 006F
120
+ oacute 00F3 obreve 014F ocircumflex 00F4 odieresis 00F6 oe 0153 ogonek 02DB
121
+ ograve 00F2 ohorn 01A1 ohungarumlaut 0151 omacron 014D omega 03C9
122
+ omega1 03D6 omegatonos 03CE omicron 03BF omicrontonos 03CC one 0031
123
+ onedotenleader 2024 oneeighth 215B onehalf 00BD onequarter 00BC
124
+ onethird 2153 openbullet 25E6 ordfeminine 00AA ordmasculine 00BA
125
+ orthogonal 221F oslash 00F8 oslashacute 01FF otilde 00F5 p 0070
126
+ paragraph 00B6 parenleft 0028 parenright 0029 partialdiff 2202 percent 0025
127
+ period 002E periodcentered 00B7 perpendicular 22A5 perthousand 2030
128
+ peseta 20A7 phi 03C6 phi1 03D5 pi 03C0 plus 002B plusminus 00B1
129
+ prescription 211E product 220F propersubset 2282 propersuperset 2283
130
+ proportional 221D psi 03C8 q 0071 question 003F questiondown 00BF
131
+ quotedbl 0022 quotedblbase 201E quotedblleft 201C quotedblright 201D
132
+ quoteleft 2018 quotereversed 201B quoteright 2019 quotesinglbase 201A
133
+ quotesingle 0027 r 0072 racute 0155 radical 221A rcaron 0159
134
+ reflexsubset 2286 reflexsuperset 2287 registered 00AE revlogicalnot 2310
135
+ rho 03C1 ring 02DA rtblock 2590 s 0073 sacute 015B scaron 0161 scedilla 015F
136
+ scircumflex 015D second 2033 section 00A7 semicolon 003B seven 0037
137
+ seveneighths 215E shade 2592 sigma 03C3 sigma1 03C2 similar 223C six 0036
138
+ slash 002F smileface 263A space 0020 spade 2660 sterling 00A3 suchthat 220B
139
+ summation 2211 sun 263C t 0074 tau 03C4 tbar 0167 tcaron 0165 therefore 2234
140
+ theta 03B8 theta1 03D1 thorn 00FE three 0033 threeeighths 215C
141
+ threequarters 00BE tilde 02DC tildecomb 0303 tonos 0384 trademark 2122
142
+ triagdn 25BC triaglf 25C4 triagrt 25BA triagup 25B2 two 0032
143
+ twodotenleader 2025 twothirds 2154 u 0075 uacute 00FA ubreve 016D
144
+ ucircumflex 00FB udieresis 00FC ugrave 00F9 uhorn 01B0 uhungarumlaut 0171
145
+ umacron 016B underscore 005F underscoredbl 2017 union 222A universal 2200
146
+ uogonek 0173 upblock 2580 upsilon 03C5 upsilondieresis 03CB
147
+ upsilondieresistonos 03B0 upsilontonos 03CD uring 016F utilde 0169 v 0076
148
+ w 0077 wacute 1E83 wcircumflex 0175 wdieresis 1E85 weierstrass 2118
149
+ wgrave 1E81 x 0078 xi 03BE y 0079 yacute 00FD ycircumflex 0177
150
+ ydieresis 00FF yen 00A5 ygrave 1EF3 z 007A zacute 017A zcaron 017E
151
+ zdotaccent 017C zero 0030 zeta 03B6
152
+ `;
153
+ const AGL_EXTRAS = `
154
+ fi FB01 fl FB02 ff FB00 ffi FB03 ffl FB04 onesuperior 00B9 twosuperior 00B2
155
+ threesuperior 00B3 nbspace 00A0
156
+ `;
157
+ /** Code points by glyph name. */
158
+ export const GLYPH_UNICODE = new Map(`${AGLFN} ${AGL_EXTRAS}`
159
+ .trim()
160
+ .split(/\s+/)
161
+ .flatMap((word, index, words) => index % 2 === 0
162
+ ? [[word, Number.parseInt(words[index + 1], 16)]]
163
+ : []));
@@ -94,6 +94,8 @@ export function createPdfEditHandler(host) {
94
94
  const { pageIndex, elementIds, scale } = payload;
95
95
  return engine().renderPageWithout(pageIndex, elementIds, scale);
96
96
  }
97
+ case "edit-text-font":
98
+ return engine().textFont(payload.id);
97
99
  case "edit-page-layout":
98
100
  return engine().pageLayout(payload.pageIndex);
99
101
  case "edit-dispose":
@@ -0,0 +1,14 @@
1
+ import { type CffFont } from "./cff.js";
2
+ /**
3
+ * The OpenType file, or `undefined` when no glyph has a code point or the
4
+ * program's name cannot be made one a browser accepts.
5
+ */
6
+ export declare function cffOpenType(program: Uint8Array, font: CffFont, unicode: ReadonlyMap<number, number>): Uint8Array | undefined;
7
+ /**
8
+ * An embedded TrueType or OpenType program with the OS/2, name and post
9
+ * tables it lacks, laid out on four-byte boundaries; `undefined` when its
10
+ * table directory or core tables are broken.
11
+ */
12
+ export declare function completeSfnt(program: Uint8Array, fontName: string): Uint8Array | undefined;
13
+ /** The sfnt file maps Unicode: a cmap subtable for platform 0, or for Windows Unicode BMP or full repertoire. */
14
+ export declare function hasUnicodeCmap(program: Uint8Array): boolean;