web-doc 0.9.0 → 0.11.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 (48) hide show
  1. package/THIRD_PARTY_NOTICES.md +14 -0
  2. package/dist/adapters/office.js +6 -3
  3. package/dist/contracts.d.ts +9 -0
  4. package/dist/edit/docx/engine.d.ts +9 -1
  5. package/dist/edit/docx/engine.js +22 -0
  6. package/dist/edit/docx/provider.d.ts +3 -1
  7. package/dist/edit/docx/provider.js +3 -0
  8. package/dist/edit/docx/session.d.ts +6 -2
  9. package/dist/edit/docx/session.js +7 -1
  10. package/dist/edit/docx/style.d.ts +1 -1
  11. package/dist/edit/docx/style.js +3 -2
  12. package/dist/edit/docx/types.d.ts +11 -1
  13. package/dist/edit/pdf/engine/cff.d.ts +28 -0
  14. package/dist/edit/pdf/engine/cff.js +416 -0
  15. package/dist/edit/pdf/engine/document.d.ts +3 -1
  16. package/dist/edit/pdf/engine/document.js +21 -1
  17. package/dist/edit/pdf/engine/elements.d.ts +7 -0
  18. package/dist/edit/pdf/engine/elements.js +12 -1
  19. package/dist/edit/pdf/engine/existing-text.js +6 -4
  20. package/dist/edit/pdf/engine/glyph-names.d.ts +2 -0
  21. package/dist/edit/pdf/engine/glyph-names.js +163 -0
  22. package/dist/edit/pdf/engine/handler.js +2 -0
  23. package/dist/edit/pdf/engine/opentype.d.ts +14 -0
  24. package/dist/edit/pdf/engine/opentype.js +317 -0
  25. package/dist/edit/pdf/engine/text-font.d.ts +4 -0
  26. package/dist/edit/pdf/engine/text-font.js +81 -0
  27. package/dist/edit/pdf/provider.d.ts +3 -1
  28. package/dist/edit/pdf/provider.js +3 -0
  29. package/dist/edit/pdf/session.d.ts +2 -1
  30. package/dist/edit/pdf/session.js +3 -0
  31. package/dist/edit/pdf/types.d.ts +40 -0
  32. package/dist/edit/pptx/elements.d.ts +4 -1
  33. package/dist/edit/pptx/elements.js +35 -0
  34. package/dist/edit/pptx/engine.d.ts +5 -1
  35. package/dist/edit/pptx/engine.js +11 -0
  36. package/dist/edit/pptx/handler.js +8 -0
  37. package/dist/edit/pptx/provider.d.ts +3 -1
  38. package/dist/edit/pptx/provider.js +3 -0
  39. package/dist/edit/pptx/session.d.ts +13 -4
  40. package/dist/edit/pptx/session.js +48 -4
  41. package/dist/edit/pptx/types.d.ts +11 -1
  42. package/dist/edit/range-style.d.ts +24 -0
  43. package/dist/edit/range-style.js +46 -0
  44. package/dist/viewport.js +83 -20
  45. package/dist/worker-protocol.d.ts +1 -1
  46. package/dist/workers/ooxml-edit-worker.js +90 -2
  47. package/dist/workers/pdf-edit-worker.js +1118 -184
  48. package/package.json +1 -1
@@ -49,5 +49,19 @@ The release artifact contains or depends on the following principal components.
49
49
  `packages/viewer/src/edit/pptx/`, `packages/viewer/src/edit/docx/` and
50
50
  `packages/viewer/src/edit/ai/` are web-doc's own; no GenOffice code is
51
51
  included.
52
+ - [Adobe Glyph List and Adobe Glyph List For New Fonts](https://github.com/adobe-type-tools/agl-aglfn) — BSD-3-Clause; the glyph names and code points in `packages/viewer/src/edit/pdf/engine/glyph-names.ts` (AGLFN 1.7 and nine AGL 2.0 entries), which give an embedded CFF font a Unicode cmap. The ISOAdobe glyph names in `packages/viewer/src/edit/pdf/engine/cff.ts` are the standard strings of the CFF specification (Adobe Technical Note 5176). Their license:
53
+
54
+ > Copyright 2002-2019 Adobe (http://www.adobe.com/).
55
+
56
+ > Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
57
+
58
+ > Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
59
+
60
+ > Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
61
+
62
+ > Neither the name of Adobe nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
63
+
64
+ > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65
+
52
66
  - [Noto Sans](https://github.com/notofonts/noto-fonts) and [Noto Sans CJK](https://github.com/notofonts/noto-cjk) subset fonts — SIL Open Font License 1.1. The font manifest, complete OFL text, pinned source commits and SHA-256 hashes are included in `dist/fonts/`.
53
67
  No Microsoft proprietary font or copyleft runtime component is bundled. Transitive notices and license expressions are verified by `npm run licenses`.
@@ -32,7 +32,7 @@ export class OfficeDocumentAdapter {
32
32
  : (await import("../edit/pptx/provider.js")).loadPptxEditEngine(original, context, this.#options.edit ?? {}),
33
33
  createSession: (core, access) => core.format === "docx"
34
34
  ? new DocxSession(core, access)
35
- : new PptxSession(core),
35
+ : new PptxSession(core, access),
36
36
  };
37
37
  formats = [...MODERN_FORMATS, ...LEGACY_FORMATS];
38
38
  #options;
@@ -86,7 +86,6 @@ export class OfficeDocumentAdapter {
86
86
  useGoogleFonts: false,
87
87
  maxZipEntryBytes: context.limits.maxZipEntryBytes,
88
88
  mode: "main",
89
- ...(reopening ? { progressiveLayout: true } : {}),
90
89
  };
91
90
  try {
92
91
  const kind = kindFor(format);
@@ -113,7 +112,10 @@ export class OfficeDocumentAdapter {
113
112
  }
114
113
  const buffer = exactArrayBuffer(data);
115
114
  if (kind === "presentation") {
116
- const backend = await this.#loadPptx(buffer, engineOptions);
115
+ const backend = await this.#loadPptx(buffer, {
116
+ ...engineOptions,
117
+ ...(reopening ? { progressiveLayout: true } : {}),
118
+ });
117
119
  throwIfAborted(context.signal, backend);
118
120
  context.reportProgress({
119
121
  phase: "parsing",
@@ -309,6 +311,7 @@ export class OfficeDocumentAdapter {
309
311
  y: run.shapeY + run.inShapeY,
310
312
  width: run.w,
311
313
  height: run.h,
314
+ shapeOrigin: { x: run.shapeX, y: run.shapeY },
312
315
  ...safeHyperlink(run.hyperlink, (ref) => handle.backend.resolveInternalTarget?.(ref, pageIndex)),
313
316
  direction: textDirection(run.text),
314
317
  }));
@@ -195,6 +195,15 @@ export interface TextRun {
195
195
  * source paragraph.
196
196
  */
197
197
  readonly paragraphId?: string;
198
+ /**
199
+ * PPTX: the top-left corner of the frame of the shape the run was laid out
200
+ * in, in the run coordinate space (slide CSS pixels). Text a shape paints
201
+ * past its frame, wrapped below a short box, still names its shape.
202
+ */
203
+ readonly shapeOrigin?: {
204
+ readonly x: number;
205
+ readonly y: number;
206
+ };
198
207
  }
199
208
  export type HyperlinkTarget = {
200
209
  readonly kind: "external";
@@ -3,10 +3,12 @@ import type { BatchMode, EditEngine, EngineBatch, EngineChange, MaterializedDocu
3
3
  import { OoxmlPackage } from "../ooxml/package.js";
4
4
  import type { EditFindOptions, EditOperation, ElementQuery, OperationIssue, PagePoint, TextTarget } from "../types.js";
5
5
  import { DocxModel, type AnyRecord } from "./model.js";
6
- import type { DocxElement, DocxRevision } from "./types.js";
6
+ import type { DocxElement, DocxRevision, DocxTextStyle } from "./types.js";
7
+ import { type TextSpan } from "../range-style.js";
7
8
  /** Reads the DOCX session adds on top of the core, served by the engine and the worker client alike. */
8
9
  export interface DocxEngineReads {
9
10
  revisions(id: string, signal: AbortSignal): Promise<readonly DocxRevision[]>;
11
+ textStyle(id: string, span: TextSpan | undefined, signal: AbortSignal): Promise<Partial<DocxTextStyle> | undefined>;
10
12
  }
11
13
  export declare class DocxEditEngine implements EditEngine, DocxEngineReads {
12
14
  #private;
@@ -25,6 +27,12 @@ export declare class DocxEditEngine implements EditEngine, DocxEngineReads {
25
27
  apply(input: EngineBatch | readonly EditOperation[], signal: AbortSignal): Promise<EngineChange>;
26
28
  /** The revisions of a paragraph; none for another element or an unknown id. */
27
29
  revisions(id: string, signal: AbortSignal): Promise<readonly DocxRevision[]>;
30
+ /**
31
+ * The style a span of a paragraph shows: what every run it covers shares;
32
+ * the paragraph mark's for an empty paragraph. None for another element,
33
+ * an unknown id or a span past the text.
34
+ */
35
+ textStyle(id: string, span: TextSpan | undefined, signal: AbortSignal): Promise<Partial<DocxTextStyle> | undefined>;
28
36
  materialize(purposeOrSignal?: "show" | "save" | AbortSignal, options?: MaterializeOptions, signal?: AbortSignal): Promise<Uint8Array>;
29
37
  /**
30
38
  * `save` is the package as the session changed it: ids written only on
@@ -7,9 +7,11 @@ import { NO_PAGE, toElement } from "./elements.js";
7
7
  import { docxHandlers } from "./handlers.js";
8
8
  import { freshParagraphId, paragraphsOf } from "./ids.js";
9
9
  import { DocxModel } from "./model.js";
10
+ import { resolveTextStyle } from "./style.js";
10
11
  import { issueCollector, } from "./operations.js";
11
12
  import { docxOperationSchemas } from "./schemas.js";
12
13
  import { revisionsOf } from "./tracked.js";
14
+ import { runsCovering, sharedStyle, spanFits, } from "../range-style.js";
13
15
  import { attributeProblem, namespacePatches } from "./write.js";
14
16
  /*
15
17
  * The DOCX edit engine: the package layer under a block index of the body
@@ -303,6 +305,26 @@ export class DocxEditEngine {
303
305
  return [];
304
306
  return revisionsOf(model.document, record.node);
305
307
  }
308
+ /**
309
+ * The style a span of a paragraph shows: what every run it covers shares;
310
+ * the paragraph mark's for an empty paragraph. None for another element,
311
+ * an unknown id or a span past the text.
312
+ */
313
+ async textStyle(id, span, signal) {
314
+ const model = await this.model(signal);
315
+ const record = model.byId.get(id);
316
+ if (!record || record.kind !== "paragraph")
317
+ return undefined;
318
+ const { text, items } = record.text;
319
+ const range = span ?? { start: 0, end: text.length };
320
+ if (!spanFits(range, text.length))
321
+ return undefined;
322
+ const covered = runsCovering(items, range);
323
+ const mark = record.pPr?.children.find((child) => child.local === "rPr");
324
+ return sharedStyle(covered.length > 0
325
+ ? covered.map((item) => resolveTextStyle(model.styles, record.pPr, item.rPr))
326
+ : [resolveTextStyle(model.styles, record.pPr, mark)]);
327
+ }
306
328
  async materialize(purposeOrSignal = "show", options = {}, signal = new AbortController().signal) {
307
329
  return (await this.materializeDocument(purposeOrSignal, options, signal))
308
330
  .bytes;
@@ -2,7 +2,8 @@ import type { EditEngineContext } from "../engine.js";
2
2
  import { type OoxmlEditProviderOptions } from "../ooxml/worker.js";
3
3
  import { WorkerEngineClient } from "../worker-engine.js";
4
4
  import type { DocxEngineReads } from "./engine.js";
5
- import type { DocxRevision } from "./types.js";
5
+ import type { TextSpan } from "../range-style.js";
6
+ import type { DocxRevision, DocxTextStyle } from "./types.js";
6
7
  export type DocxEditProviderOptions = OoxmlEditProviderOptions;
7
8
  /**
8
9
  * Starts the OOXML edit worker for `original` as a DOCX engine. Loaded
@@ -12,5 +13,6 @@ export declare function loadDocxEditEngine(original: Uint8Array, context: EditEn
12
13
  export declare class DocxEditEngineClient extends WorkerEngineClient implements DocxEngineReads {
13
14
  readonly schemas: import("../types.js").OperationSchemaSet;
14
15
  revisions(id: string, signal: AbortSignal): Promise<readonly DocxRevision[]>;
16
+ textStyle(id: string, span: TextSpan | undefined, signal: AbortSignal): Promise<Partial<DocxTextStyle> | undefined>;
15
17
  start(original: Uint8Array): Promise<void>;
16
18
  }
@@ -24,6 +24,9 @@ export class DocxEditEngineClient extends WorkerEngineClient {
24
24
  revisions(id, signal) {
25
25
  return this.request("edit-docx-revisions", { id }, signal);
26
26
  }
27
+ textStyle(id, span, signal) {
28
+ return this.request("edit-docx-text-style", { id, span }, signal);
29
+ }
27
30
  async start(original) {
28
31
  const data = original.slice().buffer;
29
32
  const open = {
@@ -1,7 +1,7 @@
1
1
  import type { DescribeOptions, DocumentDescription, EditCheckpoint, OutlineOptions, OutlineResult, TargetCandidate, TargetQuery, ToolCall, ToolCallOptions, ToolResult, ToolSet } from "../ai/types.js";
2
2
  import type { EditSessionAccess, EditSessionCore } from "../engine.js";
3
- import type { ApplyOptions, AssetOptions, EditFindOptions, EditOperation, EditReceipt, EditState, ElementQuery, HistoryOptions, OperationSchemaSet, PagePoint, PageRect, ReadItem, ReadOptions, ReadResult, SavedDocument, TextTarget } from "../types.js";
4
- import type { DocxDeleteElementOperation, DocxEditSession, DocxElement, DocxFields, DocxInsertImageOperation, DocxInsertParagraphOperation, DocxInsertTableOperation, DocxMoveElementOperation, DocxOperation, DocxReplaceTextOperation, DocxRevision, DocxSaveOptions, DocxSetParagraphStyleOperation, DocxSetTableCellOperation, DocxSetTextStyleOperation } from "./types.js";
3
+ import type { ApplyOptions, AssetOptions, EditFindOptions, EditOperation, EditReceipt, EditState, ElementQuery, HistoryOptions, OperationSchemaSet, PagePoint, PageRect, ReadItem, ReadOptions, ReadResult, SavedDocument, TextRange, TextTarget } from "../types.js";
4
+ import type { DocxDeleteElementOperation, DocxEditSession, DocxElement, DocxFields, DocxInsertImageOperation, DocxInsertParagraphOperation, DocxInsertTableOperation, DocxMoveElementOperation, DocxOperation, DocxReplaceTextOperation, DocxRevision, DocxSaveOptions, DocxSetParagraphStyleOperation, DocxSetTableCellOperation, DocxSetTextStyleOperation, DocxTextStyle } from "./types.js";
5
5
  /** Per paragraph id (eight hex digits), the union of its runs per page. */
6
6
  type Placement = ReadonlyMap<string, ReadonlyMap<number, PageRect>>;
7
7
  export declare class DocxSession implements DocxEditSession {
@@ -33,6 +33,10 @@ export declare class DocxSession implements DocxEditSession {
33
33
  get tools(): ToolSet;
34
34
  callTool(call: ToolCall, options?: ToolCallOptions): Promise<ToolResult>;
35
35
  getRevisions(elementId: string, options?: ReadOptions): Promise<ReadResult<DocxRevision>>;
36
+ getTextStyle(fields: {
37
+ readonly target: string;
38
+ readonly range?: TextRange;
39
+ }, options?: ReadOptions): Promise<ReadItem<Partial<DocxTextStyle>>>;
36
40
  replaceText(fields: DocxFields<DocxReplaceTextOperation>, options?: ApplyOptions): Promise<EditReceipt>;
37
41
  setTextStyle(fields: DocxFields<DocxSetTextStyleOperation>, options?: ApplyOptions): Promise<EditReceipt>;
38
42
  setParagraphStyle(fields: DocxFields<DocxSetParagraphStyleOperation>, options?: ApplyOptions): Promise<EditReceipt>;
@@ -2,6 +2,7 @@ import { readDescription, readOutline } from "../ai/outline.js";
2
2
  import { resolveTargets } from "../ai/targets.js";
3
3
  import { buildToolSet, callTool as runTool } from "../ai/tools.js";
4
4
  import { ViewerError } from "../../errors.js";
5
+ import { spanOnTarget } from "../range-style.js";
5
6
  export class DocxSession {
6
7
  format = "docx";
7
8
  #core;
@@ -134,6 +135,10 @@ export class DocxSession {
134
135
  getRevisions(elementId, options) {
135
136
  return this.#core.readItems(options, (engine, signal) => docxReads(engine).revisions(elementId, signal));
136
137
  }
138
+ async getTextStyle(fields, options) {
139
+ const span = spanOnTarget(fields.target, fields.range);
140
+ return this.#core.readItem(options, (engine, signal) => docxReads(engine).textStyle(fields.target, span, signal));
141
+ }
137
142
  replaceText(fields, options) {
138
143
  return this.apply([{ op: "replaceText", ...fields }], options);
139
144
  }
@@ -461,7 +466,8 @@ function matchesQuery(element, query) {
461
466
  }
462
467
  function docxReads(engine) {
463
468
  const candidate = engine;
464
- if (typeof candidate.revisions !== "function")
469
+ if (typeof candidate.revisions !== "function" ||
470
+ typeof candidate.textStyle !== "function")
465
471
  throw new ViewerError("edit-unsupported", "The engine does not provide the DOCX reads", { details: { format: "docx", reason: "no-reads" } });
466
472
  return candidate;
467
473
  }
@@ -34,7 +34,7 @@ export declare class DocxStyles {
34
34
  /** A style and the styles it is based on, nearest first; cycles stop. */
35
35
  chain(id: string | undefined): StyleRecord[];
36
36
  }
37
- /** `w:b`, `w:i`, `w:default`-style toggles: present without a value means on. */
37
+ /** `w:b`/`w:i` toggle values: a present element without `w:val` means on. */
38
38
  export declare function isOn(value: string | undefined): boolean;
39
39
  /** The run property holders in resolution order for a run of a paragraph. */
40
40
  export declare function runPropertySources(styles: DocxStyles, pPr: XmlElement | undefined, rPr: XmlElement | undefined): readonly XmlElement[];
@@ -95,11 +95,12 @@ export class DocxStyles {
95
95
  if (!id)
96
96
  continue;
97
97
  const basedOn = part.attribute(node.children.find((child) => child.local === "basedOn") ?? node, "w:val");
98
+ const defaultAttribute = part.attribute(node, "w:default");
98
99
  const record = {
99
100
  id,
100
101
  type: part.attribute(node, "w:type") ?? "paragraph",
101
102
  ...(basedOn && basedOn !== id ? { basedOn } : {}),
102
- isDefault: isOn(part.attribute(node, "w:default")),
103
+ isDefault: defaultAttribute !== undefined && isOn(defaultAttribute),
103
104
  ...pick(node, "rPr", "pPr"),
104
105
  };
105
106
  styles.set(id, record);
@@ -175,7 +176,7 @@ async function readTheme(pkg, themePart, signal) {
175
176
  return none;
176
177
  }
177
178
  }
178
- /** `w:b`, `w:i`, `w:default`-style toggles: present without a value means on. */
179
+ /** `w:b`/`w:i` toggle values: a present element without `w:val` means on. */
179
180
  export function isOn(value) {
180
181
  return value === undefined || !/^(0|false|off)$/i.test(value);
181
182
  }
@@ -1,4 +1,4 @@
1
- import type { ApplyOptions, BinaryData, EditColor, EditElement, EditReceipt, EditSessionBase, ReadOptions, ReadResult, SavedDocument, SaveOptions, TextRange } from "../types.js";
1
+ import type { ApplyOptions, BinaryData, EditColor, EditElement, EditReceipt, EditSessionBase, ReadItem, ReadOptions, ReadResult, SavedDocument, SaveOptions, TextRange } from "../types.js";
2
2
  export type DocxElementKind = "paragraph" | "table" | "image" | "other";
3
3
  export type DocxTextAlign = "left" | "center" | "right" | "justify";
4
4
  /** Word's sixteen highlight colours (`w:highlight/@w:val`). */
@@ -193,6 +193,16 @@ export interface DocxEditSession extends EditSessionBase<DocxOperation, DocxElem
193
193
  save(options?: DocxSaveOptions): Promise<SavedDocument>;
194
194
  /** The tracked changes a paragraph holds, in document order; empty for other elements. */
195
195
  getRevisions(elementId: string, options?: ReadOptions): Promise<ReadResult<DocxRevision>>;
196
+ /**
197
+ * The text style a range of a paragraph shows: each property every run it
198
+ * covers shares, a property they differ on left out. Without a range, the
199
+ * whole text; a collapsed range reads the run before it, whose style text
200
+ * typed there takes. `undefined` for an element without text.
201
+ */
202
+ getTextStyle(fields: {
203
+ readonly target: string;
204
+ readonly range?: TextRange;
205
+ }, options?: ReadOptions): Promise<ReadItem<Partial<DocxTextStyle>>>;
196
206
  /** Replaces the whole text of a paragraph, or the part a range covers. */
197
207
  replaceText(fields: DocxFields<DocxReplaceTextOperation>, options?: ApplyOptions): Promise<EditReceipt>;
198
208
  /** Changes run properties; unspecified ones keep their bytes. */
@@ -0,0 +1,28 @@
1
+ /** What a browser font is built from. */
2
+ export interface CffFont {
3
+ /** The font's PostScript name, a subset tag included. */
4
+ readonly name: string;
5
+ /** CID-keyed: glyphs are numbered, not named, and only the PDF's CMap says what they draw. */
6
+ readonly cid: boolean;
7
+ /** Glyph names by glyph id; `undefined` where the name is not one this reader knows. */
8
+ readonly glyphNames: readonly (string | undefined)[];
9
+ /** Advance widths by glyph id, in font units. */
10
+ readonly widths: readonly number[];
11
+ readonly bbox: readonly [number, number, number, number];
12
+ readonly unitsPerEm: number;
13
+ }
14
+ /**
15
+ * The code point a glyph name stands for: an Adobe Glyph List name, or
16
+ * `uniXXXX` or `uXXXX[XX]` for one code point. Ligatures of several code
17
+ * points, suffixed variants such as `a.sc`, and noncharacters stand for none.
18
+ */
19
+ export declare function glyphUnicode(name: string | undefined): number | undefined;
20
+ /** Reads a CFF font program, or `undefined` when it is not one this reader can use. */
21
+ export declare function readCff(bytes: Uint8Array): CffFont | undefined;
22
+ /**
23
+ * A copy of the program whose font name holds only what a browser's font
24
+ * sanitizer accepts in a CFF table: printable ASCII without
25
+ * `[](){}<>/%` or a space, each other byte becoming `_`; `undefined` past
26
+ * the 127 characters it accepts or for a program that is not one font.
27
+ */
28
+ export declare function cffWithSafeName(bytes: Uint8Array): Uint8Array | undefined;