web-doc 0.11.0 → 0.12.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.
- package/dist/adapters/pdf.js +19 -8
- package/dist/edit/engine.d.ts +2 -1
- package/dist/edit/pdf/engine/document.d.ts +4 -2
- package/dist/edit/pdf/engine/document.js +115 -12
- package/dist/edit/pdf/engine/elements.d.ts +5 -1
- package/dist/edit/pdf/engine/elements.js +88 -6
- package/dist/edit/pdf/engine/existing-text.js +16 -61
- package/dist/edit/pdf/engine/fonts.d.ts +14 -0
- package/dist/edit/pdf/engine/fonts.js +114 -0
- package/dist/edit/pdf/engine/handler.js +2 -0
- package/dist/edit/pdf/engine/layout.js +1 -1
- package/dist/edit/pdf/engine/operations.d.ts +7 -1
- package/dist/edit/pdf/engine/paragraph-edit.d.ts +4 -0
- package/dist/edit/pdf/engine/paragraph-edit.js +331 -0
- package/dist/edit/pdf/engine/paragraph.d.ts +31 -0
- package/dist/edit/pdf/engine/paragraph.js +445 -0
- package/dist/edit/pdf/engine/pdfium.d.ts +3 -0
- package/dist/edit/pdf/engine/text-box.js +16 -3
- package/dist/edit/pdf/engine/text-font.js +2 -19
- package/dist/edit/pdf/engine/transform.js +14 -3
- package/dist/edit/pdf/provider.d.ts +3 -1
- package/dist/edit/pdf/provider.js +3 -0
- package/dist/edit/pdf/range-map.d.ts +2 -1
- package/dist/edit/pdf/range-map.js +38 -8
- package/dist/edit/pdf/schemas.d.ts +2 -0
- package/dist/edit/pdf/schemas.js +37 -0
- package/dist/edit/pdf/session.d.ts +3 -1
- package/dist/edit/pdf/session.js +35 -6
- package/dist/edit/pdf/types.d.ts +38 -8
- package/dist/edit/session.js +5 -0
- package/dist/edit/types.d.ts +13 -0
- package/dist/viewport.js +11 -0
- package/dist/worker-protocol.d.ts +1 -1
- package/dist/workers/pdf-edit-worker.js +2019 -1003
- package/package.json +1 -1
|
@@ -3415,8 +3415,8 @@ var init_index_browser = __esm({
|
|
|
3415
3415
|
var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
|
|
3416
3416
|
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
|
|
3417
3417
|
var newSize = Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536));
|
|
3418
|
-
var
|
|
3419
|
-
if (
|
|
3418
|
+
var replacement2 = growMemory(newSize);
|
|
3419
|
+
if (replacement2) {
|
|
3420
3420
|
return true;
|
|
3421
3421
|
}
|
|
3422
3422
|
}
|
|
@@ -5799,6 +5799,15 @@ var pdfOperationSchemas = Object.freeze({
|
|
|
5799
5799
|
},
|
|
5800
5800
|
["target", "style"]
|
|
5801
5801
|
),
|
|
5802
|
+
replaceParagraphText: operation(
|
|
5803
|
+
"replaceParagraphText",
|
|
5804
|
+
{
|
|
5805
|
+
target: { $ref: "#/$defs/target" },
|
|
5806
|
+
text: { type: "string", maxLength: 2e4 },
|
|
5807
|
+
range: { $ref: "#/$defs/textRange" }
|
|
5808
|
+
},
|
|
5809
|
+
["target", "text"]
|
|
5810
|
+
),
|
|
5802
5811
|
resizeElement: operation(
|
|
5803
5812
|
"resizeElement",
|
|
5804
5813
|
{
|
|
@@ -5990,6 +5999,37 @@ var textBoxMarkSchema = {
|
|
|
5990
5999
|
},
|
|
5991
6000
|
$defs: definitions
|
|
5992
6001
|
};
|
|
6002
|
+
var paragraphMarkSchema = {
|
|
6003
|
+
type: "object",
|
|
6004
|
+
required: ["kind", "id", "rect", "text", "lines", "style", "baselineOffset"],
|
|
6005
|
+
additionalProperties: false,
|
|
6006
|
+
properties: {
|
|
6007
|
+
kind: { const: "paragraph" },
|
|
6008
|
+
id: { $ref: "#/$defs/target" },
|
|
6009
|
+
rect: { $ref: "#/$defs/rect" },
|
|
6010
|
+
text: { type: "string", maxLength: 2e4 },
|
|
6011
|
+
baselineOffset: { type: "number", minimum: 0, maximum: 2 },
|
|
6012
|
+
lines: {
|
|
6013
|
+
type: "array",
|
|
6014
|
+
maxItems: 2e4,
|
|
6015
|
+
items: { type: "string", maxLength: 2e4 }
|
|
6016
|
+
},
|
|
6017
|
+
style: {
|
|
6018
|
+
type: "object",
|
|
6019
|
+
required: [
|
|
6020
|
+
"fontFamily",
|
|
6021
|
+
"fontSize",
|
|
6022
|
+
"bold",
|
|
6023
|
+
"italic",
|
|
6024
|
+
"color",
|
|
6025
|
+
"lineHeight"
|
|
6026
|
+
],
|
|
6027
|
+
additionalProperties: false,
|
|
6028
|
+
properties: definitions.textBoxStyle.properties
|
|
6029
|
+
}
|
|
6030
|
+
},
|
|
6031
|
+
$defs: definitions
|
|
6032
|
+
};
|
|
5993
6033
|
|
|
5994
6034
|
// src/edit/schema.ts
|
|
5995
6035
|
var BASE64 = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
@@ -6336,6 +6376,20 @@ var MARK_NAME = "WebDoc";
|
|
|
6336
6376
|
var MARK_PARAM = "webdoc";
|
|
6337
6377
|
var FLAG_ITALIC = 1 << 6;
|
|
6338
6378
|
var FLAG_FORCE_BOLD = 1 << 18;
|
|
6379
|
+
function paragraphSpecOf(mark) {
|
|
6380
|
+
return validateSchema(mark, paragraphMarkSchema, 0).length === 0 ? mark : void 0;
|
|
6381
|
+
}
|
|
6382
|
+
function paragraphBounds(spec, geometry) {
|
|
6383
|
+
if (geometry.rotation === 0) return spec.rect;
|
|
6384
|
+
const upright = { ...geometry, rotation: 0 };
|
|
6385
|
+
const top = pageToUser(upright, spec.rect.x, spec.rect.y);
|
|
6386
|
+
const bottom = pageToUser(
|
|
6387
|
+
upright,
|
|
6388
|
+
spec.rect.x + spec.rect.width,
|
|
6389
|
+
spec.rect.y + spec.rect.height
|
|
6390
|
+
);
|
|
6391
|
+
return roundRect(userRectToPage(geometry, top.x, bottom.y, bottom.x, top.y));
|
|
6392
|
+
}
|
|
6339
6393
|
function scanPage(pdfium, page, textPage, pageIndex, geometry, records) {
|
|
6340
6394
|
const { lib } = pdfium;
|
|
6341
6395
|
const byObject = /* @__PURE__ */ new Map();
|
|
@@ -6368,7 +6422,7 @@ function scanPage(pdfium, page, textPage, pageIndex, geometry, records) {
|
|
|
6368
6422
|
elements: elements.map((element) => {
|
|
6369
6423
|
const members = groups.get(element.id);
|
|
6370
6424
|
const record = members && records.find((entry) => entry.id === element.id);
|
|
6371
|
-
return members && record?.mark ? compositeElement(record.mark, members, pageIndex) : element;
|
|
6425
|
+
return members && record?.mark ? compositeElement(record.mark, members, pageIndex, geometry) : element;
|
|
6372
6426
|
}),
|
|
6373
6427
|
byObject
|
|
6374
6428
|
};
|
|
@@ -6403,6 +6457,8 @@ function isValidMark(params) {
|
|
|
6403
6457
|
switch (params.kind) {
|
|
6404
6458
|
case "textBox":
|
|
6405
6459
|
return validateSchema(params, textBoxMarkSchema, 0).length === 0;
|
|
6460
|
+
case "paragraph":
|
|
6461
|
+
return validateSchema(params, paragraphMarkSchema, 0).length === 0;
|
|
6406
6462
|
case "table":
|
|
6407
6463
|
return validateSchema(params, tableMarkSchema, 0).length === 0 || validateSchema(params, tableMemberMarkSchema, 0).length === 0;
|
|
6408
6464
|
default:
|
|
@@ -6419,11 +6475,50 @@ function markIsFresh(pdfium, page, textPage, geometry, mark, indexes) {
|
|
|
6419
6475
|
objects.filter((object) => lib.FPDFPageObj_GetType(object) === OBJECT_TEXT).map((object) => textOf(pdfium, object, textPage)).join(" ")
|
|
6420
6476
|
);
|
|
6421
6477
|
const tolerance = 2;
|
|
6422
|
-
if (mark.kind === "
|
|
6478
|
+
if (mark.kind === "paragraph") {
|
|
6479
|
+
const spec = paragraphSpecOf(mark);
|
|
6480
|
+
if (!spec || objects.some((object) => {
|
|
6481
|
+
if (lib.FPDFPageObj_GetType(object) !== OBJECT_TEXT) {
|
|
6482
|
+
if (spec.text.trim().length !== 0 || lib.FPDFPageObj_GetType(object) !== OBJECT_PATH)
|
|
6483
|
+
return true;
|
|
6484
|
+
const mode = pdfium.readNumbers(
|
|
6485
|
+
2,
|
|
6486
|
+
"i32",
|
|
6487
|
+
([fill, stroke]) => lib.FPDFPath_GetDrawMode(object, fill, stroke)
|
|
6488
|
+
);
|
|
6489
|
+
const color = pdfium.readNumbers(
|
|
6490
|
+
4,
|
|
6491
|
+
"i32",
|
|
6492
|
+
([r, g, b, a]) => lib.FPDFPageObj_GetFillColor(object, r, g, b, a)
|
|
6493
|
+
);
|
|
6494
|
+
return mode?.[0] !== 1 || mode[1] !== 0 || color?.[3] !== 0;
|
|
6495
|
+
}
|
|
6496
|
+
const current = textStyle(pdfium, object);
|
|
6497
|
+
return current.fontSize !== round(spec.style.fontSize) || current.color !== spec.style.color || current.bold !== spec.style.bold || current.italic !== spec.style.italic;
|
|
6498
|
+
}))
|
|
6499
|
+
return false;
|
|
6500
|
+
const frame = paragraphBounds(spec, geometry);
|
|
6501
|
+
if (union.y + union.height > frame.y + frame.height + tolerance)
|
|
6502
|
+
return false;
|
|
6503
|
+
const nativeLines = objects.filter((object) => lib.FPDFPageObj_GetType(object) === OBJECT_TEXT).map((object) => textOf(pdfium, object, textPage).trimEnd());
|
|
6504
|
+
if (nativeLines.length !== spec.lines.length || nativeLines.some((line, index) => line !== spec.lines[index]))
|
|
6505
|
+
return false;
|
|
6506
|
+
let cursor = 0;
|
|
6507
|
+
for (const line of nativeLines) {
|
|
6508
|
+
while (!spec.text.startsWith(line, cursor) && cursor < spec.text.length && /\s/u.test(spec.text[cursor]))
|
|
6509
|
+
cursor += 1;
|
|
6510
|
+
if (!spec.text.startsWith(line, cursor)) return false;
|
|
6511
|
+
cursor += line.length;
|
|
6512
|
+
}
|
|
6513
|
+
if (spec.text.slice(cursor).trim()) return false;
|
|
6514
|
+
if (geometry.rotation !== 0)
|
|
6515
|
+
return union.x >= frame.x - tolerance && union.y >= frame.y - tolerance && union.x + union.width <= frame.x + frame.width + tolerance;
|
|
6516
|
+
}
|
|
6517
|
+
if (mark.kind === "textBox" || mark.kind === "paragraph") {
|
|
6423
6518
|
const rect = mark.rect;
|
|
6424
6519
|
const text = mark.text;
|
|
6425
6520
|
const style2 = mark.style;
|
|
6426
|
-
return drawn === normalizeText(text) && union.x >= rect.x - tolerance && union.x + union.width <= rect.x + rect.width + tolerance && // The first line's ink starts inside the box's first line band; the
|
|
6521
|
+
return (mark.kind === "paragraph" || drawn === normalizeText(text)) && union.x >= rect.x - tolerance && union.x + union.width <= rect.x + rect.width + tolerance && // The first line's ink starts inside the box's first line band; the
|
|
6427
6522
|
// bottom is not checked because overflowing text runs past the box.
|
|
6428
6523
|
union.y >= rect.y - tolerance && union.y <= rect.y + style2.fontSize * style2.lineHeight + tolerance;
|
|
6429
6524
|
}
|
|
@@ -6479,7 +6574,7 @@ function plainElement(pdfium, object, textPage, record, pageIndex, geometry) {
|
|
|
6479
6574
|
return { ...base, kind: "other", operations: TRANSFORM_OPERATIONS };
|
|
6480
6575
|
}
|
|
6481
6576
|
}
|
|
6482
|
-
function compositeElement(mark, members, pageIndex) {
|
|
6577
|
+
function compositeElement(mark, members, pageIndex, geometry) {
|
|
6483
6578
|
const bounds = roundRect(unionRects(members.map((member) => member.bounds)));
|
|
6484
6579
|
const text = members.filter((member) => member.kind === "text" && member.text).map((member) => member.text).join("\n");
|
|
6485
6580
|
if (mark.kind === "table") {
|
|
@@ -6502,6 +6597,23 @@ function compositeElement(mark, members, pageIndex) {
|
|
|
6502
6597
|
operations: TABLE_OPERATIONS
|
|
6503
6598
|
};
|
|
6504
6599
|
}
|
|
6600
|
+
const paragraph = paragraphSpecOf(mark);
|
|
6601
|
+
if (paragraph)
|
|
6602
|
+
return {
|
|
6603
|
+
id: mark.id,
|
|
6604
|
+
kind: "paragraph",
|
|
6605
|
+
pageIndex,
|
|
6606
|
+
bounds: paragraphBounds(paragraph, geometry),
|
|
6607
|
+
text: paragraph.text,
|
|
6608
|
+
textStyle: paragraph.style,
|
|
6609
|
+
...geometry.rotation ? { rotation: geometry.rotation * 90 } : {},
|
|
6610
|
+
operations: geometry.rotation ? ["deleteElement"] : [
|
|
6611
|
+
"replaceText",
|
|
6612
|
+
"replaceParagraphText",
|
|
6613
|
+
"setTextStyle",
|
|
6614
|
+
"deleteElement"
|
|
6615
|
+
]
|
|
6616
|
+
};
|
|
6505
6617
|
const style = members.find((member) => member.textStyle)?.textStyle;
|
|
6506
6618
|
return {
|
|
6507
6619
|
id: mark.id,
|
|
@@ -6639,7 +6751,7 @@ function objectRotation(pdfium, object, geometry) {
|
|
|
6639
6751
|
|
|
6640
6752
|
// src/edit/pdf/engine/layout.ts
|
|
6641
6753
|
var HIT_TOLERANCE = 2;
|
|
6642
|
-
var TEXT_KINDS = /* @__PURE__ */ new Set(["text", "textBox", "table"]);
|
|
6754
|
+
var TEXT_KINDS = /* @__PURE__ */ new Set(["text", "textBox", "table", "paragraph"]);
|
|
6643
6755
|
function layoutOf(pdfium, scan, element) {
|
|
6644
6756
|
if (!TEXT_KINDS.has(element.kind)) return void 0;
|
|
6645
6757
|
const glyphs = glyphsOf(
|
|
@@ -6775,10 +6887,10 @@ function linesOf(pdfium, scan, glyphs) {
|
|
|
6775
6887
|
text: members.map((glyph) => glyph.char).join(""),
|
|
6776
6888
|
bounds: roundRect(unionRects(members.map((glyph) => glyph.box))),
|
|
6777
6889
|
baseline: members[0].origin,
|
|
6778
|
-
glyphs: members.map(({ position, box, advance }) => ({
|
|
6890
|
+
glyphs: members.map(({ position, box, advance: advance2 }) => ({
|
|
6779
6891
|
offset: position.offset,
|
|
6780
6892
|
box,
|
|
6781
|
-
advance
|
|
6893
|
+
advance: advance2
|
|
6782
6894
|
})),
|
|
6783
6895
|
fontFamily: style.fontFamily,
|
|
6784
6896
|
fontSize: style.fontSize,
|
|
@@ -6811,893 +6923,989 @@ function roundPoint(point) {
|
|
|
6811
6923
|
return { x: round(point.x), y: round(point.y) };
|
|
6812
6924
|
}
|
|
6813
6925
|
|
|
6814
|
-
// src/edit/pdf/engine/
|
|
6815
|
-
var
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6926
|
+
// src/edit/pdf/engine/glyph-names.ts
|
|
6927
|
+
var AGLFN = `
|
|
6928
|
+
A 0041 AE 00C6 AEacute 01FC Aacute 00C1 Abreve 0102 Acircumflex 00C2
|
|
6929
|
+
Adieresis 00C4 Agrave 00C0 Alpha 0391 Alphatonos 0386 Amacron 0100
|
|
6930
|
+
Aogonek 0104 Aring 00C5 Aringacute 01FA Atilde 00C3 B 0042 Beta 0392 C 0043
|
|
6931
|
+
Cacute 0106 Ccaron 010C Ccedilla 00C7 Ccircumflex 0108 Cdotaccent 010A
|
|
6932
|
+
Chi 03A7 D 0044 Dcaron 010E Dcroat 0110 Delta 2206 E 0045 Eacute 00C9
|
|
6933
|
+
Ebreve 0114 Ecaron 011A Ecircumflex 00CA Edieresis 00CB Edotaccent 0116
|
|
6934
|
+
Egrave 00C8 Emacron 0112 Eng 014A Eogonek 0118 Epsilon 0395
|
|
6935
|
+
Epsilontonos 0388 Eta 0397 Etatonos 0389 Eth 00D0 Euro 20AC F 0046 G 0047
|
|
6936
|
+
Gamma 0393 Gbreve 011E Gcaron 01E6 Gcircumflex 011C Gdotaccent 0120 H 0048
|
|
6937
|
+
H18533 25CF H18543 25AA H18551 25AB H22073 25A1 Hbar 0126 Hcircumflex 0124
|
|
6938
|
+
I 0049 IJ 0132 Iacute 00CD Ibreve 012C Icircumflex 00CE Idieresis 00CF
|
|
6939
|
+
Idotaccent 0130 Ifraktur 2111 Igrave 00CC Imacron 012A Iogonek 012E
|
|
6940
|
+
Iota 0399 Iotadieresis 03AA Iotatonos 038A Itilde 0128 J 004A
|
|
6941
|
+
Jcircumflex 0134 K 004B Kappa 039A L 004C Lacute 0139 Lambda 039B
|
|
6942
|
+
Lcaron 013D Ldot 013F Lslash 0141 M 004D Mu 039C N 004E Nacute 0143
|
|
6943
|
+
Ncaron 0147 Ntilde 00D1 Nu 039D O 004F OE 0152 Oacute 00D3 Obreve 014E
|
|
6944
|
+
Ocircumflex 00D4 Odieresis 00D6 Ograve 00D2 Ohorn 01A0 Ohungarumlaut 0150
|
|
6945
|
+
Omacron 014C Omega 2126 Omegatonos 038F Omicron 039F Omicrontonos 038C
|
|
6946
|
+
Oslash 00D8 Oslashacute 01FE Otilde 00D5 P 0050 Phi 03A6 Pi 03A0 Psi 03A8
|
|
6947
|
+
Q 0051 R 0052 Racute 0154 Rcaron 0158 Rfraktur 211C Rho 03A1 S 0053
|
|
6948
|
+
SF010000 250C SF020000 2514 SF030000 2510 SF040000 2518 SF050000 253C
|
|
6949
|
+
SF060000 252C SF070000 2534 SF080000 251C SF090000 2524 SF100000 2500
|
|
6950
|
+
SF110000 2502 SF190000 2561 SF200000 2562 SF210000 2556 SF220000 2555
|
|
6951
|
+
SF230000 2563 SF240000 2551 SF250000 2557 SF260000 255D SF270000 255C
|
|
6952
|
+
SF280000 255B SF360000 255E SF370000 255F SF380000 255A SF390000 2554
|
|
6953
|
+
SF400000 2569 SF410000 2566 SF420000 2560 SF430000 2550 SF440000 256C
|
|
6954
|
+
SF450000 2567 SF460000 2568 SF470000 2564 SF480000 2565 SF490000 2559
|
|
6955
|
+
SF500000 2558 SF510000 2552 SF520000 2553 SF530000 256B SF540000 256A
|
|
6956
|
+
Sacute 015A Scaron 0160 Scedilla 015E Scircumflex 015C Sigma 03A3 T 0054
|
|
6957
|
+
Tau 03A4 Tbar 0166 Tcaron 0164 Theta 0398 Thorn 00DE U 0055 Uacute 00DA
|
|
6958
|
+
Ubreve 016C Ucircumflex 00DB Udieresis 00DC Ugrave 00D9 Uhorn 01AF
|
|
6959
|
+
Uhungarumlaut 0170 Umacron 016A Uogonek 0172 Upsilon 03A5 Upsilon1 03D2
|
|
6960
|
+
Upsilondieresis 03AB Upsilontonos 038E Uring 016E Utilde 0168 V 0056 W 0057
|
|
6961
|
+
Wacute 1E82 Wcircumflex 0174 Wdieresis 1E84 Wgrave 1E80 X 0058 Xi 039E
|
|
6962
|
+
Y 0059 Yacute 00DD Ycircumflex 0176 Ydieresis 0178 Ygrave 1EF2 Z 005A
|
|
6963
|
+
Zacute 0179 Zcaron 017D Zdotaccent 017B Zeta 0396 a 0061 aacute 00E1
|
|
6964
|
+
abreve 0103 acircumflex 00E2 acute 00B4 acutecomb 0301 adieresis 00E4
|
|
6965
|
+
ae 00E6 aeacute 01FD agrave 00E0 aleph 2135 alpha 03B1 alphatonos 03AC
|
|
6966
|
+
amacron 0101 ampersand 0026 angle 2220 angleleft 2329 angleright 232A
|
|
6967
|
+
anoteleia 0387 aogonek 0105 approxequal 2248 aring 00E5 aringacute 01FB
|
|
6968
|
+
arrowboth 2194 arrowdblboth 21D4 arrowdbldown 21D3 arrowdblleft 21D0
|
|
6969
|
+
arrowdblright 21D2 arrowdblup 21D1 arrowdown 2193 arrowleft 2190
|
|
6970
|
+
arrowright 2192 arrowup 2191 arrowupdn 2195 arrowupdnbse 21A8
|
|
6971
|
+
asciicircum 005E asciitilde 007E asterisk 002A asteriskmath 2217 at 0040
|
|
6972
|
+
atilde 00E3 b 0062 backslash 005C bar 007C beta 03B2 block 2588
|
|
6973
|
+
braceleft 007B braceright 007D bracketleft 005B bracketright 005D breve 02D8
|
|
6974
|
+
brokenbar 00A6 bullet 2022 c 0063 cacute 0107 caron 02C7 carriagereturn 21B5
|
|
6975
|
+
ccaron 010D ccedilla 00E7 ccircumflex 0109 cdotaccent 010B cedilla 00B8
|
|
6976
|
+
cent 00A2 chi 03C7 circle 25CB circlemultiply 2297 circleplus 2295
|
|
6977
|
+
circumflex 02C6 club 2663 colon 003A colonmonetary 20A1 comma 002C
|
|
6978
|
+
congruent 2245 copyright 00A9 currency 00A4 d 0064 dagger 2020
|
|
6979
|
+
daggerdbl 2021 dcaron 010F dcroat 0111 degree 00B0 delta 03B4 diamond 2666
|
|
6980
|
+
dieresis 00A8 dieresistonos 0385 divide 00F7 dkshade 2593 dnblock 2584
|
|
6981
|
+
dollar 0024 dong 20AB dotaccent 02D9 dotbelowcomb 0323 dotlessi 0131
|
|
6982
|
+
dotmath 22C5 e 0065 eacute 00E9 ebreve 0115 ecaron 011B ecircumflex 00EA
|
|
6983
|
+
edieresis 00EB edotaccent 0117 egrave 00E8 eight 0038 element 2208
|
|
6984
|
+
ellipsis 2026 emacron 0113 emdash 2014 emptyset 2205 endash 2013 eng 014B
|
|
6985
|
+
eogonek 0119 epsilon 03B5 epsilontonos 03AD equal 003D equivalence 2261
|
|
6986
|
+
estimated 212E eta 03B7 etatonos 03AE eth 00F0 exclam 0021 exclamdbl 203C
|
|
6987
|
+
exclamdown 00A1 existential 2203 f 0066 female 2640 figuredash 2012
|
|
6988
|
+
filledbox 25A0 filledrect 25AC five 0035 fiveeighths 215D florin 0192
|
|
6989
|
+
four 0034 fraction 2044 franc 20A3 g 0067 gamma 03B3 gbreve 011F gcaron 01E7
|
|
6990
|
+
gcircumflex 011D gdotaccent 0121 germandbls 00DF gradient 2207 grave 0060
|
|
6991
|
+
gravecomb 0300 greater 003E greaterequal 2265 guillemotleft 00AB
|
|
6992
|
+
guillemotright 00BB guilsinglleft 2039 guilsinglright 203A h 0068 hbar 0127
|
|
6993
|
+
hcircumflex 0125 heart 2665 hookabovecomb 0309 house 2302 hungarumlaut 02DD
|
|
6994
|
+
hyphen 002D i 0069 iacute 00ED ibreve 012D icircumflex 00EE idieresis 00EF
|
|
6995
|
+
igrave 00EC ij 0133 imacron 012B infinity 221E integral 222B integralbt 2321
|
|
6996
|
+
integraltp 2320 intersection 2229 invbullet 25D8 invcircle 25D9
|
|
6997
|
+
invsmileface 263B iogonek 012F iota 03B9 iotadieresis 03CA
|
|
6998
|
+
iotadieresistonos 0390 iotatonos 03AF itilde 0129 j 006A jcircumflex 0135
|
|
6999
|
+
k 006B kappa 03BA kgreenlandic 0138 l 006C lacute 013A lambda 03BB
|
|
7000
|
+
lcaron 013E ldot 0140 less 003C lessequal 2264 lfblock 258C lira 20A4
|
|
7001
|
+
logicaland 2227 logicalnot 00AC logicalor 2228 longs 017F lozenge 25CA
|
|
7002
|
+
lslash 0142 ltshade 2591 m 006D macron 00AF male 2642 minus 2212 minute 2032
|
|
7003
|
+
mu 00B5 multiply 00D7 musicalnote 266A musicalnotedbl 266B n 006E
|
|
7004
|
+
nacute 0144 napostrophe 0149 ncaron 0148 nine 0039 notelement 2209
|
|
7005
|
+
notequal 2260 notsubset 2284 ntilde 00F1 nu 03BD numbersign 0023 o 006F
|
|
7006
|
+
oacute 00F3 obreve 014F ocircumflex 00F4 odieresis 00F6 oe 0153 ogonek 02DB
|
|
7007
|
+
ograve 00F2 ohorn 01A1 ohungarumlaut 0151 omacron 014D omega 03C9
|
|
7008
|
+
omega1 03D6 omegatonos 03CE omicron 03BF omicrontonos 03CC one 0031
|
|
7009
|
+
onedotenleader 2024 oneeighth 215B onehalf 00BD onequarter 00BC
|
|
7010
|
+
onethird 2153 openbullet 25E6 ordfeminine 00AA ordmasculine 00BA
|
|
7011
|
+
orthogonal 221F oslash 00F8 oslashacute 01FF otilde 00F5 p 0070
|
|
7012
|
+
paragraph 00B6 parenleft 0028 parenright 0029 partialdiff 2202 percent 0025
|
|
7013
|
+
period 002E periodcentered 00B7 perpendicular 22A5 perthousand 2030
|
|
7014
|
+
peseta 20A7 phi 03C6 phi1 03D5 pi 03C0 plus 002B plusminus 00B1
|
|
7015
|
+
prescription 211E product 220F propersubset 2282 propersuperset 2283
|
|
7016
|
+
proportional 221D psi 03C8 q 0071 question 003F questiondown 00BF
|
|
7017
|
+
quotedbl 0022 quotedblbase 201E quotedblleft 201C quotedblright 201D
|
|
7018
|
+
quoteleft 2018 quotereversed 201B quoteright 2019 quotesinglbase 201A
|
|
7019
|
+
quotesingle 0027 r 0072 racute 0155 radical 221A rcaron 0159
|
|
7020
|
+
reflexsubset 2286 reflexsuperset 2287 registered 00AE revlogicalnot 2310
|
|
7021
|
+
rho 03C1 ring 02DA rtblock 2590 s 0073 sacute 015B scaron 0161 scedilla 015F
|
|
7022
|
+
scircumflex 015D second 2033 section 00A7 semicolon 003B seven 0037
|
|
7023
|
+
seveneighths 215E shade 2592 sigma 03C3 sigma1 03C2 similar 223C six 0036
|
|
7024
|
+
slash 002F smileface 263A space 0020 spade 2660 sterling 00A3 suchthat 220B
|
|
7025
|
+
summation 2211 sun 263C t 0074 tau 03C4 tbar 0167 tcaron 0165 therefore 2234
|
|
7026
|
+
theta 03B8 theta1 03D1 thorn 00FE three 0033 threeeighths 215C
|
|
7027
|
+
threequarters 00BE tilde 02DC tildecomb 0303 tonos 0384 trademark 2122
|
|
7028
|
+
triagdn 25BC triaglf 25C4 triagrt 25BA triagup 25B2 two 0032
|
|
7029
|
+
twodotenleader 2025 twothirds 2154 u 0075 uacute 00FA ubreve 016D
|
|
7030
|
+
ucircumflex 00FB udieresis 00FC ugrave 00F9 uhorn 01B0 uhungarumlaut 0171
|
|
7031
|
+
umacron 016B underscore 005F underscoredbl 2017 union 222A universal 2200
|
|
7032
|
+
uogonek 0173 upblock 2580 upsilon 03C5 upsilondieresis 03CB
|
|
7033
|
+
upsilondieresistonos 03B0 upsilontonos 03CD uring 016F utilde 0169 v 0076
|
|
7034
|
+
w 0077 wacute 1E83 wcircumflex 0175 wdieresis 1E85 weierstrass 2118
|
|
7035
|
+
wgrave 1E81 x 0078 xi 03BE y 0079 yacute 00FD ycircumflex 0177
|
|
7036
|
+
ydieresis 00FF yen 00A5 ygrave 1EF3 z 007A zacute 017A zcaron 017E
|
|
7037
|
+
zdotaccent 017C zero 0030 zeta 03B6
|
|
7038
|
+
`;
|
|
7039
|
+
var AGL_EXTRAS = `
|
|
7040
|
+
fi FB01 fl FB02 ff FB00 ffi FB03 ffl FB04 onesuperior 00B9 twosuperior 00B2
|
|
7041
|
+
threesuperior 00B3 nbspace 00A0
|
|
7042
|
+
`;
|
|
7043
|
+
var GLYPH_UNICODE = new Map(
|
|
7044
|
+
`${AGLFN} ${AGL_EXTRAS}`.trim().split(/\s+/).flatMap(
|
|
7045
|
+
(word, index, words) => index % 2 === 0 ? [[word, Number.parseInt(words[index + 1], 16)]] : []
|
|
7046
|
+
)
|
|
6832
7047
|
);
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
7048
|
+
|
|
7049
|
+
// src/edit/pdf/engine/cff.ts
|
|
7050
|
+
var ISO_ADOBE_NAMES = `
|
|
7051
|
+
.notdef space exclam quotedbl numbersign dollar percent ampersand
|
|
7052
|
+
quoteright parenleft parenright asterisk plus comma hyphen period slash
|
|
7053
|
+
zero one two three four five six seven eight nine colon semicolon less
|
|
7054
|
+
equal greater question at A B C D E F G H I J K L M N O P Q R S T U V W X Y
|
|
7055
|
+
Z bracketleft backslash bracketright asciicircum underscore quoteleft a b c
|
|
7056
|
+
d e f g h i j k l m n o p q r s t u v w x y z braceleft bar braceright
|
|
7057
|
+
asciitilde exclamdown cent sterling fraction yen florin section currency
|
|
7058
|
+
quotesingle quotedblleft guillemotleft guilsinglleft guilsinglright fi fl
|
|
7059
|
+
endash dagger daggerdbl periodcentered paragraph bullet quotesinglbase
|
|
7060
|
+
quotedblbase quotedblright guillemotright ellipsis perthousand questiondown
|
|
7061
|
+
grave acute circumflex tilde macron breve dotaccent dieresis ring cedilla
|
|
7062
|
+
hungarumlaut ogonek caron emdash AE ordfeminine Lslash Oslash OE
|
|
7063
|
+
ordmasculine ae dotlessi lslash oslash oe germandbls onesuperior logicalnot
|
|
7064
|
+
mu trademark Eth onehalf plusminus Thorn onequarter divide brokenbar degree
|
|
7065
|
+
thorn threequarters twosuperior registered minus eth multiply threesuperior
|
|
7066
|
+
copyright Aacute Acircumflex Adieresis Agrave Aring Atilde Ccedilla Eacute
|
|
7067
|
+
Ecircumflex Edieresis Egrave Iacute Icircumflex Idieresis Igrave Ntilde
|
|
7068
|
+
Oacute Ocircumflex Odieresis Ograve Otilde Scaron Uacute Ucircumflex
|
|
7069
|
+
Udieresis Ugrave Yacute Ydieresis Zcaron aacute acircumflex adieresis
|
|
7070
|
+
agrave aring atilde ccedilla eacute ecircumflex edieresis egrave iacute
|
|
7071
|
+
icircumflex idieresis igrave ntilde oacute ocircumflex odieresis ograve
|
|
7072
|
+
otilde scaron uacute ucircumflex udieresis ugrave yacute ydieresis zcaron
|
|
7073
|
+
`.trim().split(/\s+/);
|
|
7074
|
+
function glyphUnicode(name) {
|
|
7075
|
+
if (!name || name === ".notdef") return void 0;
|
|
7076
|
+
const known = GLYPH_UNICODE.get(name);
|
|
7077
|
+
if (known !== void 0) return known;
|
|
7078
|
+
const match = /^uni([0-9A-F]{4})$|^u([0-9A-F]{4,6})$/.exec(name);
|
|
7079
|
+
const hex2 = match?.[1] ?? match?.[2];
|
|
7080
|
+
if (!hex2) return void 0;
|
|
7081
|
+
const code = Number.parseInt(hex2, 16);
|
|
7082
|
+
const surrogate = code >= 55296 && code <= 57343;
|
|
7083
|
+
const nonCharacter = (code & 65534) === 65534;
|
|
7084
|
+
return code <= 1114111 && !surrogate && !nonCharacter ? code : void 0;
|
|
6852
7085
|
}
|
|
6853
|
-
var
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
const
|
|
6882
|
-
|
|
6883
|
-
);
|
|
6884
|
-
const
|
|
6885
|
-
|
|
6886
|
-
);
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
7086
|
+
var OP = {
|
|
7087
|
+
fontBBox: 5,
|
|
7088
|
+
charset: 15,
|
|
7089
|
+
charStrings: 17,
|
|
7090
|
+
private: 18,
|
|
7091
|
+
defaultWidthX: 20,
|
|
7092
|
+
nominalWidthX: 21,
|
|
7093
|
+
subrs: 19,
|
|
7094
|
+
charstringType: 1206,
|
|
7095
|
+
fontMatrix: 1207,
|
|
7096
|
+
ros: 1230
|
|
7097
|
+
};
|
|
7098
|
+
var STANDARD_STRINGS = 391;
|
|
7099
|
+
function readCff(bytes2) {
|
|
7100
|
+
try {
|
|
7101
|
+
const at = (offset2) => {
|
|
7102
|
+
if (!Number.isInteger(offset2) || offset2 < 0 || offset2 >= bytes2.length)
|
|
7103
|
+
throw new RangeError("Outside the font");
|
|
7104
|
+
return bytes2[offset2];
|
|
7105
|
+
};
|
|
7106
|
+
const u162 = (offset2) => at(offset2) << 8 | at(offset2 + 1);
|
|
7107
|
+
if (at(0) !== 1) return void 0;
|
|
7108
|
+
const names2 = readIndex(bytes2, at(2), at, u162);
|
|
7109
|
+
const tops = readIndex(bytes2, names2.end, at, u162);
|
|
7110
|
+
const strings = readIndex(bytes2, tops.end, at, u162);
|
|
7111
|
+
const globalSubrs = readIndex(bytes2, strings.end, at, u162);
|
|
7112
|
+
if (names2.items.length !== 1 || tops.items.length !== 1) return void 0;
|
|
7113
|
+
const top = readDict(bytes2, ...tops.items[0], at);
|
|
7114
|
+
const charStringsAt = top.get(OP.charStrings)?.[0];
|
|
7115
|
+
if (charStringsAt === void 0) return void 0;
|
|
7116
|
+
if ((top.get(OP.charstringType)?.[0] ?? 2) !== 2) return void 0;
|
|
7117
|
+
const charStrings = readIndex(bytes2, charStringsAt, at, u162);
|
|
7118
|
+
const glyphCount = charStrings.items.length;
|
|
7119
|
+
if (glyphCount === 0) return void 0;
|
|
7120
|
+
const [scale = 1e-3, skewX = 0, skewY = 0, scaleY = 1e-3] = top.get(OP.fontMatrix) ?? [];
|
|
7121
|
+
if (skewX !== 0 || skewY !== 0 || scale !== scaleY || scale <= 0)
|
|
7122
|
+
return void 0;
|
|
7123
|
+
const unitsPerEm = Math.round(1 / scale);
|
|
7124
|
+
if (unitsPerEm < 16 || unitsPerEm > 16384) return void 0;
|
|
7125
|
+
const [xMin = 0, yMin = 0, xMax = 0, yMax = 0] = top.get(OP.fontBBox) ?? [];
|
|
7126
|
+
const cid = top.has(OP.ros);
|
|
7127
|
+
const [nameStart, nameEnd] = names2.items[0];
|
|
7128
|
+
const name = latin1(
|
|
7129
|
+
bytes2.subarray(nameStart, Math.min(nameEnd, nameStart + 127))
|
|
6894
7130
|
);
|
|
6895
|
-
if (
|
|
6896
|
-
this.#fallback = await this.#fetch(this.#fallbackUrl);
|
|
6897
|
-
}
|
|
6898
|
-
/** Checks a request against what is loaded; `undefined` means it will resolve. */
|
|
6899
|
-
problem(request) {
|
|
6900
|
-
const standard = isStandardFamily(request.family);
|
|
6901
|
-
if (!standard && !this.hasFamily(request.family))
|
|
7131
|
+
if (cid)
|
|
6902
7132
|
return {
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
7133
|
+
name,
|
|
7134
|
+
cid,
|
|
7135
|
+
glyphNames: [],
|
|
7136
|
+
widths: [],
|
|
7137
|
+
bbox: [xMin, yMin, xMax, yMax],
|
|
7138
|
+
unitsPerEm
|
|
6906
7139
|
};
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
return void 0;
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
7140
|
+
const custom = /* @__PURE__ */ new Map();
|
|
7141
|
+
const stringOf = (sid) => {
|
|
7142
|
+
if (sid < ISO_ADOBE_NAMES.length) return ISO_ADOBE_NAMES[sid];
|
|
7143
|
+
const item = strings.items[sid - STANDARD_STRINGS];
|
|
7144
|
+
if (!item) return void 0;
|
|
7145
|
+
if (!custom.has(sid))
|
|
7146
|
+
custom.set(
|
|
7147
|
+
sid,
|
|
7148
|
+
// A glyph name is 63 characters at most.
|
|
7149
|
+
item[1] - item[0] <= 63 ? latin1(bytes2.subarray(...item)) : void 0
|
|
7150
|
+
);
|
|
7151
|
+
return custom.get(sid);
|
|
6917
7152
|
};
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
if (registered) {
|
|
6935
|
-
const exact = isBold(registered.font) === request.bold && isItalic(registered.font) === request.italic;
|
|
6936
|
-
return {
|
|
6937
|
-
handle: this.#load(pdfium, document2, registered.bytes),
|
|
6938
|
-
family: registered.font.family,
|
|
6939
|
-
...exact ? {} : {
|
|
6940
|
-
substitution: `${registered.font.family} has no matching bold or italic face`
|
|
6941
|
-
}
|
|
6942
|
-
};
|
|
6943
|
-
}
|
|
6944
|
-
if (!this.#fallback || !this.#covers(this.#fallback, request.text))
|
|
6945
|
-
throw new Error(`No font covers "${request.text}"`);
|
|
6946
|
-
return {
|
|
6947
|
-
handle: this.#load(pdfium, document2, this.#fallback),
|
|
6948
|
-
family: FALLBACK_FAMILY,
|
|
6949
|
-
substitution: `${request.family} cannot draw this text; ${FALLBACK_FAMILY} is used`
|
|
7153
|
+
const glyphNames = charsetNames(
|
|
7154
|
+
top.get(OP.charset)?.[0] ?? 0,
|
|
7155
|
+
glyphCount,
|
|
7156
|
+
stringOf,
|
|
7157
|
+
at,
|
|
7158
|
+
u162
|
|
7159
|
+
);
|
|
7160
|
+
const [privateSize, privateAt] = top.get(OP.private) ?? [0, 0];
|
|
7161
|
+
const privateDict = privateSize ? readDict(bytes2, privateAt, privateAt + privateSize, at) : /* @__PURE__ */ new Map();
|
|
7162
|
+
const localAt = privateDict.get(OP.subrs)?.[0];
|
|
7163
|
+
const metrics = {
|
|
7164
|
+
bytes: bytes2,
|
|
7165
|
+
defaultWidth: privateDict.get(OP.defaultWidthX)?.[0] ?? 0,
|
|
7166
|
+
nominalWidth: privateDict.get(OP.nominalWidthX)?.[0] ?? 0,
|
|
7167
|
+
global: globalSubrs.items,
|
|
7168
|
+
local: localAt === void 0 ? [] : readIndex(bytes2, privateAt + localAt, at, u162).items
|
|
6950
7169
|
};
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
release(pdfium, document2) {
|
|
6954
|
-
const handles = this.#handles.get(document2);
|
|
6955
|
-
if (!handles) return;
|
|
6956
|
-
for (const handle of handles.values()) pdfium.lib.FPDFFont_Close(handle);
|
|
6957
|
-
this.#handles.delete(document2);
|
|
6958
|
-
}
|
|
6959
|
-
covers(bytes2, text) {
|
|
6960
|
-
return this.#covers(bytes2, text);
|
|
6961
|
-
}
|
|
6962
|
-
#coveringRegistered(request) {
|
|
6963
|
-
const candidates = this.#registered.filter((font) => sameFamily(font.family, request.family)).map((font) => ({ font, bytes: this.#loadedBytes(font) })).filter(
|
|
6964
|
-
(entry) => entry.bytes !== void 0 && this.#covers(entry.bytes, request.text)
|
|
7170
|
+
const widths = charStrings.items.map(
|
|
7171
|
+
([start, end]) => charstringWidth(metrics, start, end)
|
|
6965
7172
|
);
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
if (
|
|
6976
|
-
|
|
6977
|
-
this.#coverage.set(bytes2, coverage);
|
|
6978
|
-
}
|
|
6979
|
-
for (const character of text) {
|
|
6980
|
-
const code = character.codePointAt(0);
|
|
6981
|
-
if (code === 10 || code === 32) continue;
|
|
6982
|
-
if (!coverage.has(code)) return character;
|
|
6983
|
-
}
|
|
6984
|
-
return void 0;
|
|
7173
|
+
return {
|
|
7174
|
+
name,
|
|
7175
|
+
cid,
|
|
7176
|
+
glyphNames,
|
|
7177
|
+
widths,
|
|
7178
|
+
bbox: [xMin, yMin, xMax, yMax],
|
|
7179
|
+
unitsPerEm
|
|
7180
|
+
};
|
|
7181
|
+
} catch (error) {
|
|
7182
|
+
if (error instanceof RangeError) return void 0;
|
|
7183
|
+
throw error;
|
|
6985
7184
|
}
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
pdfium.free(pointer);
|
|
7005
|
-
}
|
|
7006
|
-
if (!handle) throw new Error("PDFium could not load the font");
|
|
7007
|
-
handles.set(bytes2, handle);
|
|
7185
|
+
}
|
|
7186
|
+
function cffWithSafeName(bytes2) {
|
|
7187
|
+
try {
|
|
7188
|
+
const at = (offset2) => {
|
|
7189
|
+
if (offset2 < 0 || offset2 >= bytes2.length)
|
|
7190
|
+
throw new RangeError("Outside the font");
|
|
7191
|
+
return bytes2[offset2];
|
|
7192
|
+
};
|
|
7193
|
+
const u162 = (offset2) => at(offset2) << 8 | at(offset2 + 1);
|
|
7194
|
+
const names2 = readIndex(bytes2, at(2), at, u162);
|
|
7195
|
+
const [start, end] = names2.items[0] ?? [0, 0];
|
|
7196
|
+
if (names2.items.length !== 1 || end - start > 127) return void 0;
|
|
7197
|
+
const safe = bytes2.slice();
|
|
7198
|
+
for (let offset2 = start; offset2 < end; offset2 += 1) {
|
|
7199
|
+
const byte = safe[offset2];
|
|
7200
|
+
if (offset2 === start && byte === 0) continue;
|
|
7201
|
+
if (byte < 33 || byte > 126 || UNSAFE_NAME_BYTES.has(byte))
|
|
7202
|
+
safe[offset2] = 95;
|
|
7008
7203
|
}
|
|
7009
|
-
return
|
|
7010
|
-
}
|
|
7011
|
-
|
|
7012
|
-
|
|
7204
|
+
return safe;
|
|
7205
|
+
} catch (error) {
|
|
7206
|
+
if (error instanceof RangeError) return void 0;
|
|
7207
|
+
throw error;
|
|
7013
7208
|
}
|
|
7014
|
-
async #bytesOf(font) {
|
|
7015
|
-
const key = sourceKey(font);
|
|
7016
|
-
let bytes2 = this.#bytes.get(key);
|
|
7017
|
-
if (!bytes2) {
|
|
7018
|
-
bytes2 = typeof font.source === "string" ? await this.#fetch(font.source) : new Uint8Array(font.source);
|
|
7019
|
-
this.#bytes.set(key, bytes2);
|
|
7020
|
-
}
|
|
7021
|
-
return bytes2;
|
|
7022
|
-
}
|
|
7023
|
-
};
|
|
7024
|
-
function sourceKey(font) {
|
|
7025
|
-
return typeof font.source === "string" ? font.source : `${font.family}:${font.weight}:${font.style}:${font.source.byteLength}`;
|
|
7026
|
-
}
|
|
7027
|
-
function sameFamily(a, b) {
|
|
7028
|
-
return a.toLowerCase() === b.toLowerCase();
|
|
7029
|
-
}
|
|
7030
|
-
function isBold(font) {
|
|
7031
|
-
return font.weight >= 600;
|
|
7032
|
-
}
|
|
7033
|
-
function isItalic(font) {
|
|
7034
|
-
return font.style !== "normal";
|
|
7035
7209
|
}
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
const
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
return
|
|
7210
|
+
var UNSAFE_NAME_BYTES = new Set(
|
|
7211
|
+
[..."[](){}<>/%"].map((character) => character.charCodeAt(0))
|
|
7212
|
+
);
|
|
7213
|
+
function readIndex(bytes2, start, at, u162) {
|
|
7214
|
+
const count = u162(start);
|
|
7215
|
+
if (count === 0) return { items: [], end: start + 2 };
|
|
7216
|
+
const offSize = at(start + 2);
|
|
7217
|
+
if (offSize < 1 || offSize > 4) throw new RangeError("Bad offset size");
|
|
7218
|
+
const offset2 = (index) => {
|
|
7219
|
+
let value = 0;
|
|
7220
|
+
for (let byte = 0; byte < offSize; byte += 1)
|
|
7221
|
+
value = value * 256 + at(start + 3 + index * offSize + byte);
|
|
7222
|
+
return value;
|
|
7049
7223
|
};
|
|
7224
|
+
if (offset2(0) !== 1) throw new RangeError("Bad INDEX");
|
|
7225
|
+
const base = start + 2 + (count + 1) * offSize;
|
|
7226
|
+
const items = [];
|
|
7227
|
+
for (let index = 0; index < count; index += 1) {
|
|
7228
|
+
const from = base + offset2(index);
|
|
7229
|
+
const to = base + offset2(index + 1);
|
|
7230
|
+
if (to < from || to > bytes2.length) throw new RangeError("Bad INDEX");
|
|
7231
|
+
items.push([from, to]);
|
|
7232
|
+
}
|
|
7233
|
+
return { items, end: base + offset2(count) };
|
|
7050
7234
|
}
|
|
7051
|
-
function
|
|
7052
|
-
|
|
7053
|
-
const
|
|
7054
|
-
|
|
7055
|
-
let
|
|
7056
|
-
|
|
7057
|
-
const
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7235
|
+
function readDict(bytes2, start, end, at) {
|
|
7236
|
+
if (end > bytes2.length) throw new RangeError("DICT past the font");
|
|
7237
|
+
const entries = /* @__PURE__ */ new Map();
|
|
7238
|
+
let operands = [];
|
|
7239
|
+
let offset2 = start;
|
|
7240
|
+
while (offset2 < end) {
|
|
7241
|
+
const byte = at(offset2);
|
|
7242
|
+
if (byte <= 21) {
|
|
7243
|
+
const operator = byte === 12 ? 1200 + at(offset2 + 1) : byte;
|
|
7244
|
+
offset2 += byte === 12 ? 2 : 1;
|
|
7245
|
+
entries.set(operator, operands);
|
|
7246
|
+
operands = [];
|
|
7247
|
+
} else if (byte === 28) {
|
|
7248
|
+
operands.push(int16(at(offset2 + 1) << 8 | at(offset2 + 2)));
|
|
7249
|
+
offset2 += 3;
|
|
7250
|
+
} else if (byte === 29) {
|
|
7251
|
+
operands.push(
|
|
7252
|
+
at(offset2 + 1) << 24 | at(offset2 + 2) << 16 | at(offset2 + 3) << 8 | at(offset2 + 4)
|
|
7067
7253
|
);
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
drawable: () => false,
|
|
7079
|
-
glyph: () => void 0
|
|
7080
|
-
};
|
|
7081
|
-
const subtables = view.getUint16(cmapOffset + 2);
|
|
7082
|
-
let best;
|
|
7083
|
-
for (let index = 0; index < subtables; index += 1) {
|
|
7084
|
-
const record = cmapOffset + 4 + index * 8;
|
|
7085
|
-
const platform = view.getUint16(record);
|
|
7086
|
-
const encoding = view.getUint16(record + 2);
|
|
7087
|
-
const offset2 = cmapOffset + view.getUint32(record + 4);
|
|
7088
|
-
const format = view.getUint16(offset2);
|
|
7089
|
-
const unicode = platform === 0 || platform === 3 && (encoding === 1 || encoding === 10);
|
|
7090
|
-
if (!unicode || format !== 4 && format !== 12) continue;
|
|
7091
|
-
if (!best || format > best.format) best = { offset: offset2, format };
|
|
7092
|
-
}
|
|
7093
|
-
if (!best)
|
|
7094
|
-
return {
|
|
7095
|
-
has: () => false,
|
|
7096
|
-
drawable: () => false,
|
|
7097
|
-
glyph: () => void 0
|
|
7098
|
-
};
|
|
7099
|
-
if (best.format === 12) {
|
|
7100
|
-
const groups = view.getUint32(best.offset + 12);
|
|
7101
|
-
for (let index = 0; index < groups; index += 1) {
|
|
7102
|
-
const group = best.offset + 16 + index * 12;
|
|
7103
|
-
const start = view.getUint32(group);
|
|
7104
|
-
const end = view.getUint32(group + 4);
|
|
7105
|
-
const startGlyph = view.getUint32(group + 8);
|
|
7106
|
-
ranges.push([start, end]);
|
|
7107
|
-
for (let code = start; code <= end && code - start < 65536; code += 1)
|
|
7108
|
-
glyphs.set(code, startGlyph + (code - start));
|
|
7109
|
-
}
|
|
7110
|
-
} else {
|
|
7111
|
-
const segments = view.getUint16(best.offset + 6) / 2;
|
|
7112
|
-
const ends = best.offset + 14;
|
|
7113
|
-
const starts = ends + segments * 2 + 2;
|
|
7114
|
-
const deltas = starts + segments * 2;
|
|
7115
|
-
const rangeOffsets = deltas + segments * 2;
|
|
7116
|
-
for (let index = 0; index < segments; index += 1) {
|
|
7117
|
-
const end = view.getUint16(ends + index * 2);
|
|
7118
|
-
const start = view.getUint16(starts + index * 2);
|
|
7119
|
-
if (start === 65535) continue;
|
|
7120
|
-
ranges.push([start, end]);
|
|
7121
|
-
const delta = view.getInt16(deltas + index * 2);
|
|
7122
|
-
const rangeOffset = view.getUint16(rangeOffsets + index * 2);
|
|
7123
|
-
for (let code = start; code <= end; code += 1) {
|
|
7124
|
-
let glyph;
|
|
7125
|
-
if (rangeOffset === 0) glyph = code + delta & 65535;
|
|
7126
|
-
else {
|
|
7127
|
-
const at = rangeOffsets + index * 2 + rangeOffset + (code - start) * 2;
|
|
7128
|
-
const raw = view.getUint16(at);
|
|
7129
|
-
glyph = raw === 0 ? 0 : raw + delta & 65535;
|
|
7254
|
+
offset2 += 5;
|
|
7255
|
+
} else if (byte === 30) {
|
|
7256
|
+
let text = "";
|
|
7257
|
+
offset2 += 1;
|
|
7258
|
+
for (let done = false; !done; offset2 += 1) {
|
|
7259
|
+
const pair = at(offset2);
|
|
7260
|
+
for (const nibble of [pair >> 4, pair & 15]) {
|
|
7261
|
+
if (nibble === 15) {
|
|
7262
|
+
done = true;
|
|
7263
|
+
break;
|
|
7130
7264
|
}
|
|
7131
|
-
|
|
7265
|
+
text += REAL_NIBBLES[nibble] ?? "";
|
|
7132
7266
|
}
|
|
7133
7267
|
}
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7268
|
+
operands.push(Number.parseFloat(text));
|
|
7269
|
+
} else if (byte >= 32 && byte <= 246) {
|
|
7270
|
+
operands.push(byte - 139);
|
|
7271
|
+
offset2 += 1;
|
|
7272
|
+
} else if (byte >= 247 && byte <= 250) {
|
|
7273
|
+
operands.push((byte - 247) * 256 + at(offset2 + 1) + 108);
|
|
7274
|
+
offset2 += 2;
|
|
7275
|
+
} else if (byte >= 251 && byte <= 254) {
|
|
7276
|
+
operands.push(-(byte - 251) * 256 - at(offset2 + 1) - 108);
|
|
7277
|
+
offset2 += 2;
|
|
7278
|
+
} else throw new RangeError("Bad DICT byte");
|
|
7137
7279
|
}
|
|
7138
|
-
|
|
7139
|
-
return {
|
|
7140
|
-
glyph(codePoint) {
|
|
7141
|
-
return glyphs.get(codePoint);
|
|
7142
|
-
},
|
|
7143
|
-
drawable(codePoint) {
|
|
7144
|
-
const glyph = glyphs.get(codePoint);
|
|
7145
|
-
if (glyph === void 0 || glyph === 0) return false;
|
|
7146
|
-
return outlines ? outlines(glyph) : true;
|
|
7147
|
-
},
|
|
7148
|
-
has(codePoint) {
|
|
7149
|
-
let low = 0;
|
|
7150
|
-
let high = ranges.length - 1;
|
|
7151
|
-
while (low <= high) {
|
|
7152
|
-
const middle = low + high >> 1;
|
|
7153
|
-
const [start, end] = ranges[middle];
|
|
7154
|
-
if (codePoint < start) high = middle - 1;
|
|
7155
|
-
else if (codePoint > end) low = middle + 1;
|
|
7156
|
-
else return true;
|
|
7157
|
-
}
|
|
7158
|
-
return false;
|
|
7159
|
-
}
|
|
7160
|
-
};
|
|
7280
|
+
return entries;
|
|
7161
7281
|
}
|
|
7162
|
-
var
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7282
|
+
var REAL_NIBBLES = [
|
|
7283
|
+
"0",
|
|
7284
|
+
"1",
|
|
7285
|
+
"2",
|
|
7286
|
+
"3",
|
|
7287
|
+
"4",
|
|
7288
|
+
"5",
|
|
7289
|
+
"6",
|
|
7290
|
+
"7",
|
|
7291
|
+
"8",
|
|
7292
|
+
"9",
|
|
7293
|
+
".",
|
|
7294
|
+
"E",
|
|
7295
|
+
"E-",
|
|
7296
|
+
"",
|
|
7297
|
+
"-"
|
|
7298
|
+
];
|
|
7299
|
+
function charsetNames(offset2, glyphCount, stringOf, at, u162) {
|
|
7300
|
+
const names2 = [".notdef"];
|
|
7301
|
+
if (offset2 === 0) {
|
|
7302
|
+
for (let glyph = 1; glyph < glyphCount; glyph += 1)
|
|
7303
|
+
names2.push(stringOf(glyph));
|
|
7304
|
+
return names2;
|
|
7176
7305
|
}
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
)
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
([pointer]) => lib.FPDFFont_GetDescent(font, 1e3, pointer)
|
|
7191
|
-
)?.[0] ?? -250;
|
|
7192
|
-
unit = { ascent, descent: Math.abs(descent) };
|
|
7193
|
-
this.#metrics.set(font, unit);
|
|
7194
|
-
}
|
|
7195
|
-
return {
|
|
7196
|
-
ascent: unit.ascent * fontSize / 1e3,
|
|
7197
|
-
descent: unit.descent * fontSize / 1e3
|
|
7198
|
-
};
|
|
7199
|
-
}
|
|
7200
|
-
#advanceOf(font, character) {
|
|
7201
|
-
let cache = this.#advances.get(font);
|
|
7202
|
-
if (!cache) {
|
|
7203
|
-
cache = /* @__PURE__ */ new Map();
|
|
7204
|
-
this.#advances.set(font, cache);
|
|
7205
|
-
}
|
|
7206
|
-
let advance = cache.get(character);
|
|
7207
|
-
if (advance === void 0) {
|
|
7208
|
-
advance = this.#inkWidth(font, `H${character}H`) - this.#inkWidth(font, "HH");
|
|
7209
|
-
cache.set(character, advance);
|
|
7306
|
+
if (offset2 <= 2) return [...names2, ...Array(glyphCount - 1)];
|
|
7307
|
+
const format = at(offset2);
|
|
7308
|
+
let cursor = offset2 + 1;
|
|
7309
|
+
if (format === 0) {
|
|
7310
|
+
for (let glyph = 1; glyph < glyphCount; glyph += 1, cursor += 2)
|
|
7311
|
+
names2.push(stringOf(u162(cursor)));
|
|
7312
|
+
} else if (format === 1 || format === 2) {
|
|
7313
|
+
while (names2.length < glyphCount) {
|
|
7314
|
+
const first = u162(cursor);
|
|
7315
|
+
const left = format === 1 ? at(cursor + 2) : u162(cursor + 2);
|
|
7316
|
+
cursor += format === 1 ? 3 : 4;
|
|
7317
|
+
for (let step = 0; step <= left && names2.length < glyphCount; step += 1)
|
|
7318
|
+
names2.push(stringOf(first + step));
|
|
7210
7319
|
}
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7320
|
+
} else throw new RangeError("Bad charset format");
|
|
7321
|
+
return names2;
|
|
7322
|
+
}
|
|
7323
|
+
function charstringWidth(context, start, end) {
|
|
7324
|
+
const { bytes: bytes2, defaultWidth, nominalWidth } = context;
|
|
7325
|
+
const stack = [];
|
|
7326
|
+
const walk = (from, to, depth) => {
|
|
7327
|
+
let offset2 = from;
|
|
7328
|
+
while (offset2 < to) {
|
|
7329
|
+
const byte = bytes2[offset2];
|
|
7330
|
+
const size = byte === 28 ? 3 : byte === 255 ? 5 : byte >= 247 && byte <= 254 ? 2 : 1;
|
|
7331
|
+
if (offset2 + size > to) return defaultWidth;
|
|
7332
|
+
if (byte === 28 || byte >= 32) {
|
|
7333
|
+
const next = (step) => bytes2[offset2 + step];
|
|
7334
|
+
stack.push(
|
|
7335
|
+
byte === 28 ? int16(next(1) << 8 | next(2)) : byte <= 246 ? byte - 139 : byte <= 250 ? (byte - 247) * 256 + next(1) + 108 : byte <= 254 ? -(byte - 251) * 256 - next(1) - 108 : (next(1) << 24 | next(2) << 16 | next(3) << 8 | next(4)) / 65536
|
|
7336
|
+
);
|
|
7337
|
+
if (stack.length > 48) return defaultWidth;
|
|
7338
|
+
offset2 += size;
|
|
7339
|
+
continue;
|
|
7222
7340
|
}
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7341
|
+
offset2 += 1;
|
|
7342
|
+
if (byte === 10 || byte === 29) {
|
|
7343
|
+
const subrs = byte === 10 ? context.local : context.global;
|
|
7344
|
+
const index = stack.pop();
|
|
7345
|
+
const subr = index === void 0 ? void 0 : subrs[index + subrBias(subrs.length)];
|
|
7346
|
+
if (!subr || depth >= 10) return defaultWidth;
|
|
7347
|
+
const width = walk(subr[0], subr[1], depth + 1);
|
|
7348
|
+
if (width !== void 0) return width;
|
|
7349
|
+
continue;
|
|
7350
|
+
}
|
|
7351
|
+
if (byte === 11) return depth > 0 ? void 0 : defaultWidth;
|
|
7352
|
+
const takes = STACK_CLEARING[byte];
|
|
7353
|
+
if (takes === void 0) return defaultWidth;
|
|
7354
|
+
const count = stack.length;
|
|
7355
|
+
const widthFirst = takes === "pairs" ? count % 2 === 1 : takes === "endchar" ? count === 1 || count === 5 : count > takes;
|
|
7356
|
+
return widthFirst ? stack[0] + nominalWidth : defaultWidth;
|
|
7231
7357
|
}
|
|
7232
|
-
|
|
7358
|
+
return depth > 0 ? void 0 : defaultWidth;
|
|
7359
|
+
};
|
|
7360
|
+
return walk(start, end, 0) ?? defaultWidth;
|
|
7361
|
+
}
|
|
7362
|
+
function subrBias(count) {
|
|
7363
|
+
return count < 1240 ? 107 : count < 33900 ? 1131 : 32768;
|
|
7364
|
+
}
|
|
7365
|
+
var STACK_CLEARING = {
|
|
7366
|
+
1: "pairs",
|
|
7367
|
+
// hstem
|
|
7368
|
+
3: "pairs",
|
|
7369
|
+
// vstem
|
|
7370
|
+
18: "pairs",
|
|
7371
|
+
// hstemhm
|
|
7372
|
+
23: "pairs",
|
|
7373
|
+
// vstemhm
|
|
7374
|
+
19: "pairs",
|
|
7375
|
+
// hintmask, after implied vstems
|
|
7376
|
+
20: "pairs",
|
|
7377
|
+
// cntrmask
|
|
7378
|
+
21: 2,
|
|
7379
|
+
// rmoveto
|
|
7380
|
+
22: 1,
|
|
7381
|
+
// hmoveto
|
|
7382
|
+
4: 1,
|
|
7383
|
+
// vmoveto
|
|
7384
|
+
14: "endchar"
|
|
7385
|
+
// endchar: none, or four for an accented character
|
|
7233
7386
|
};
|
|
7387
|
+
function int16(value) {
|
|
7388
|
+
return value >= 32768 ? value - 65536 : value;
|
|
7389
|
+
}
|
|
7390
|
+
function latin1(bytes2) {
|
|
7391
|
+
return String.fromCharCode(...bytes2);
|
|
7392
|
+
}
|
|
7234
7393
|
|
|
7235
|
-
// src/edit/pdf/engine/
|
|
7236
|
-
var
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
Ocircumflex 00D4 Odieresis 00D6 Ograve 00D2 Ohorn 01A0 Ohungarumlaut 0150
|
|
7254
|
-
Omacron 014C Omega 2126 Omegatonos 038F Omicron 039F Omicrontonos 038C
|
|
7255
|
-
Oslash 00D8 Oslashacute 01FE Otilde 00D5 P 0050 Phi 03A6 Pi 03A0 Psi 03A8
|
|
7256
|
-
Q 0051 R 0052 Racute 0154 Rcaron 0158 Rfraktur 211C Rho 03A1 S 0053
|
|
7257
|
-
SF010000 250C SF020000 2514 SF030000 2510 SF040000 2518 SF050000 253C
|
|
7258
|
-
SF060000 252C SF070000 2534 SF080000 251C SF090000 2524 SF100000 2500
|
|
7259
|
-
SF110000 2502 SF190000 2561 SF200000 2562 SF210000 2556 SF220000 2555
|
|
7260
|
-
SF230000 2563 SF240000 2551 SF250000 2557 SF260000 255D SF270000 255C
|
|
7261
|
-
SF280000 255B SF360000 255E SF370000 255F SF380000 255A SF390000 2554
|
|
7262
|
-
SF400000 2569 SF410000 2566 SF420000 2560 SF430000 2550 SF440000 256C
|
|
7263
|
-
SF450000 2567 SF460000 2568 SF470000 2564 SF480000 2565 SF490000 2559
|
|
7264
|
-
SF500000 2558 SF510000 2552 SF520000 2553 SF530000 256B SF540000 256A
|
|
7265
|
-
Sacute 015A Scaron 0160 Scedilla 015E Scircumflex 015C Sigma 03A3 T 0054
|
|
7266
|
-
Tau 03A4 Tbar 0166 Tcaron 0164 Theta 0398 Thorn 00DE U 0055 Uacute 00DA
|
|
7267
|
-
Ubreve 016C Ucircumflex 00DB Udieresis 00DC Ugrave 00D9 Uhorn 01AF
|
|
7268
|
-
Uhungarumlaut 0170 Umacron 016A Uogonek 0172 Upsilon 03A5 Upsilon1 03D2
|
|
7269
|
-
Upsilondieresis 03AB Upsilontonos 038E Uring 016E Utilde 0168 V 0056 W 0057
|
|
7270
|
-
Wacute 1E82 Wcircumflex 0174 Wdieresis 1E84 Wgrave 1E80 X 0058 Xi 039E
|
|
7271
|
-
Y 0059 Yacute 00DD Ycircumflex 0176 Ydieresis 0178 Ygrave 1EF2 Z 005A
|
|
7272
|
-
Zacute 0179 Zcaron 017D Zdotaccent 017B Zeta 0396 a 0061 aacute 00E1
|
|
7273
|
-
abreve 0103 acircumflex 00E2 acute 00B4 acutecomb 0301 adieresis 00E4
|
|
7274
|
-
ae 00E6 aeacute 01FD agrave 00E0 aleph 2135 alpha 03B1 alphatonos 03AC
|
|
7275
|
-
amacron 0101 ampersand 0026 angle 2220 angleleft 2329 angleright 232A
|
|
7276
|
-
anoteleia 0387 aogonek 0105 approxequal 2248 aring 00E5 aringacute 01FB
|
|
7277
|
-
arrowboth 2194 arrowdblboth 21D4 arrowdbldown 21D3 arrowdblleft 21D0
|
|
7278
|
-
arrowdblright 21D2 arrowdblup 21D1 arrowdown 2193 arrowleft 2190
|
|
7279
|
-
arrowright 2192 arrowup 2191 arrowupdn 2195 arrowupdnbse 21A8
|
|
7280
|
-
asciicircum 005E asciitilde 007E asterisk 002A asteriskmath 2217 at 0040
|
|
7281
|
-
atilde 00E3 b 0062 backslash 005C bar 007C beta 03B2 block 2588
|
|
7282
|
-
braceleft 007B braceright 007D bracketleft 005B bracketright 005D breve 02D8
|
|
7283
|
-
brokenbar 00A6 bullet 2022 c 0063 cacute 0107 caron 02C7 carriagereturn 21B5
|
|
7284
|
-
ccaron 010D ccedilla 00E7 ccircumflex 0109 cdotaccent 010B cedilla 00B8
|
|
7285
|
-
cent 00A2 chi 03C7 circle 25CB circlemultiply 2297 circleplus 2295
|
|
7286
|
-
circumflex 02C6 club 2663 colon 003A colonmonetary 20A1 comma 002C
|
|
7287
|
-
congruent 2245 copyright 00A9 currency 00A4 d 0064 dagger 2020
|
|
7288
|
-
daggerdbl 2021 dcaron 010F dcroat 0111 degree 00B0 delta 03B4 diamond 2666
|
|
7289
|
-
dieresis 00A8 dieresistonos 0385 divide 00F7 dkshade 2593 dnblock 2584
|
|
7290
|
-
dollar 0024 dong 20AB dotaccent 02D9 dotbelowcomb 0323 dotlessi 0131
|
|
7291
|
-
dotmath 22C5 e 0065 eacute 00E9 ebreve 0115 ecaron 011B ecircumflex 00EA
|
|
7292
|
-
edieresis 00EB edotaccent 0117 egrave 00E8 eight 0038 element 2208
|
|
7293
|
-
ellipsis 2026 emacron 0113 emdash 2014 emptyset 2205 endash 2013 eng 014B
|
|
7294
|
-
eogonek 0119 epsilon 03B5 epsilontonos 03AD equal 003D equivalence 2261
|
|
7295
|
-
estimated 212E eta 03B7 etatonos 03AE eth 00F0 exclam 0021 exclamdbl 203C
|
|
7296
|
-
exclamdown 00A1 existential 2203 f 0066 female 2640 figuredash 2012
|
|
7297
|
-
filledbox 25A0 filledrect 25AC five 0035 fiveeighths 215D florin 0192
|
|
7298
|
-
four 0034 fraction 2044 franc 20A3 g 0067 gamma 03B3 gbreve 011F gcaron 01E7
|
|
7299
|
-
gcircumflex 011D gdotaccent 0121 germandbls 00DF gradient 2207 grave 0060
|
|
7300
|
-
gravecomb 0300 greater 003E greaterequal 2265 guillemotleft 00AB
|
|
7301
|
-
guillemotright 00BB guilsinglleft 2039 guilsinglright 203A h 0068 hbar 0127
|
|
7302
|
-
hcircumflex 0125 heart 2665 hookabovecomb 0309 house 2302 hungarumlaut 02DD
|
|
7303
|
-
hyphen 002D i 0069 iacute 00ED ibreve 012D icircumflex 00EE idieresis 00EF
|
|
7304
|
-
igrave 00EC ij 0133 imacron 012B infinity 221E integral 222B integralbt 2321
|
|
7305
|
-
integraltp 2320 intersection 2229 invbullet 25D8 invcircle 25D9
|
|
7306
|
-
invsmileface 263B iogonek 012F iota 03B9 iotadieresis 03CA
|
|
7307
|
-
iotadieresistonos 0390 iotatonos 03AF itilde 0129 j 006A jcircumflex 0135
|
|
7308
|
-
k 006B kappa 03BA kgreenlandic 0138 l 006C lacute 013A lambda 03BB
|
|
7309
|
-
lcaron 013E ldot 0140 less 003C lessequal 2264 lfblock 258C lira 20A4
|
|
7310
|
-
logicaland 2227 logicalnot 00AC logicalor 2228 longs 017F lozenge 25CA
|
|
7311
|
-
lslash 0142 ltshade 2591 m 006D macron 00AF male 2642 minus 2212 minute 2032
|
|
7312
|
-
mu 00B5 multiply 00D7 musicalnote 266A musicalnotedbl 266B n 006E
|
|
7313
|
-
nacute 0144 napostrophe 0149 ncaron 0148 nine 0039 notelement 2209
|
|
7314
|
-
notequal 2260 notsubset 2284 ntilde 00F1 nu 03BD numbersign 0023 o 006F
|
|
7315
|
-
oacute 00F3 obreve 014F ocircumflex 00F4 odieresis 00F6 oe 0153 ogonek 02DB
|
|
7316
|
-
ograve 00F2 ohorn 01A1 ohungarumlaut 0151 omacron 014D omega 03C9
|
|
7317
|
-
omega1 03D6 omegatonos 03CE omicron 03BF omicrontonos 03CC one 0031
|
|
7318
|
-
onedotenleader 2024 oneeighth 215B onehalf 00BD onequarter 00BC
|
|
7319
|
-
onethird 2153 openbullet 25E6 ordfeminine 00AA ordmasculine 00BA
|
|
7320
|
-
orthogonal 221F oslash 00F8 oslashacute 01FF otilde 00F5 p 0070
|
|
7321
|
-
paragraph 00B6 parenleft 0028 parenright 0029 partialdiff 2202 percent 0025
|
|
7322
|
-
period 002E periodcentered 00B7 perpendicular 22A5 perthousand 2030
|
|
7323
|
-
peseta 20A7 phi 03C6 phi1 03D5 pi 03C0 plus 002B plusminus 00B1
|
|
7324
|
-
prescription 211E product 220F propersubset 2282 propersuperset 2283
|
|
7325
|
-
proportional 221D psi 03C8 q 0071 question 003F questiondown 00BF
|
|
7326
|
-
quotedbl 0022 quotedblbase 201E quotedblleft 201C quotedblright 201D
|
|
7327
|
-
quoteleft 2018 quotereversed 201B quoteright 2019 quotesinglbase 201A
|
|
7328
|
-
quotesingle 0027 r 0072 racute 0155 radical 221A rcaron 0159
|
|
7329
|
-
reflexsubset 2286 reflexsuperset 2287 registered 00AE revlogicalnot 2310
|
|
7330
|
-
rho 03C1 ring 02DA rtblock 2590 s 0073 sacute 015B scaron 0161 scedilla 015F
|
|
7331
|
-
scircumflex 015D second 2033 section 00A7 semicolon 003B seven 0037
|
|
7332
|
-
seveneighths 215E shade 2592 sigma 03C3 sigma1 03C2 similar 223C six 0036
|
|
7333
|
-
slash 002F smileface 263A space 0020 spade 2660 sterling 00A3 suchthat 220B
|
|
7334
|
-
summation 2211 sun 263C t 0074 tau 03C4 tbar 0167 tcaron 0165 therefore 2234
|
|
7335
|
-
theta 03B8 theta1 03D1 thorn 00FE three 0033 threeeighths 215C
|
|
7336
|
-
threequarters 00BE tilde 02DC tildecomb 0303 tonos 0384 trademark 2122
|
|
7337
|
-
triagdn 25BC triaglf 25C4 triagrt 25BA triagup 25B2 two 0032
|
|
7338
|
-
twodotenleader 2025 twothirds 2154 u 0075 uacute 00FA ubreve 016D
|
|
7339
|
-
ucircumflex 00FB udieresis 00FC ugrave 00F9 uhorn 01B0 uhungarumlaut 0171
|
|
7340
|
-
umacron 016B underscore 005F underscoredbl 2017 union 222A universal 2200
|
|
7341
|
-
uogonek 0173 upblock 2580 upsilon 03C5 upsilondieresis 03CB
|
|
7342
|
-
upsilondieresistonos 03B0 upsilontonos 03CD uring 016F utilde 0169 v 0076
|
|
7343
|
-
w 0077 wacute 1E83 wcircumflex 0175 wdieresis 1E85 weierstrass 2118
|
|
7344
|
-
wgrave 1E81 x 0078 xi 03BE y 0079 yacute 00FD ycircumflex 0177
|
|
7345
|
-
ydieresis 00FF yen 00A5 ygrave 1EF3 z 007A zacute 017A zcaron 017E
|
|
7346
|
-
zdotaccent 017C zero 0030 zeta 03B6
|
|
7347
|
-
`;
|
|
7348
|
-
var AGL_EXTRAS = `
|
|
7349
|
-
fi FB01 fl FB02 ff FB00 ffi FB03 ffl FB04 onesuperior 00B9 twosuperior 00B2
|
|
7350
|
-
threesuperior 00B3 nbspace 00A0
|
|
7351
|
-
`;
|
|
7352
|
-
var GLYPH_UNICODE = new Map(
|
|
7353
|
-
`${AGLFN} ${AGL_EXTRAS}`.trim().split(/\s+/).flatMap(
|
|
7354
|
-
(word, index, words) => index % 2 === 0 ? [[word, Number.parseInt(words[index + 1], 16)]] : []
|
|
7355
|
-
)
|
|
7394
|
+
// src/edit/pdf/engine/fonts.ts
|
|
7395
|
+
var STANDARD_FAMILIES = {
|
|
7396
|
+
helvetica: [
|
|
7397
|
+
"Helvetica",
|
|
7398
|
+
"Helvetica-Bold",
|
|
7399
|
+
"Helvetica-Oblique",
|
|
7400
|
+
"Helvetica-BoldOblique"
|
|
7401
|
+
],
|
|
7402
|
+
times: ["Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic"],
|
|
7403
|
+
courier: [
|
|
7404
|
+
"Courier",
|
|
7405
|
+
"Courier-Bold",
|
|
7406
|
+
"Courier-Oblique",
|
|
7407
|
+
"Courier-BoldOblique"
|
|
7408
|
+
]
|
|
7409
|
+
};
|
|
7410
|
+
var WIN_ANSI_EXTRAS = new Set(
|
|
7411
|
+
"\u20AC\u201A\u0192\u201E\u2026\u2020\u2021\u02C6\u2030\u0160\u2039\u0152\u017D\u2018\u2019\u201C\u201D\u2022\u2013\u2014\u02DC\u2122\u0161\u203A\u0153\u017E\u0178".split("").map((c) => c.codePointAt(0))
|
|
7356
7412
|
);
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
.
|
|
7361
|
-
quoteright parenleft parenright asterisk plus comma hyphen period slash
|
|
7362
|
-
zero one two three four five six seven eight nine colon semicolon less
|
|
7363
|
-
equal greater question at A B C D E F G H I J K L M N O P Q R S T U V W X Y
|
|
7364
|
-
Z bracketleft backslash bracketright asciicircum underscore quoteleft a b c
|
|
7365
|
-
d e f g h i j k l m n o p q r s t u v w x y z braceleft bar braceright
|
|
7366
|
-
asciitilde exclamdown cent sterling fraction yen florin section currency
|
|
7367
|
-
quotesingle quotedblleft guillemotleft guilsinglleft guilsinglright fi fl
|
|
7368
|
-
endash dagger daggerdbl periodcentered paragraph bullet quotesinglbase
|
|
7369
|
-
quotedblbase quotedblright guillemotright ellipsis perthousand questiondown
|
|
7370
|
-
grave acute circumflex tilde macron breve dotaccent dieresis ring cedilla
|
|
7371
|
-
hungarumlaut ogonek caron emdash AE ordfeminine Lslash Oslash OE
|
|
7372
|
-
ordmasculine ae dotlessi lslash oslash oe germandbls onesuperior logicalnot
|
|
7373
|
-
mu trademark Eth onehalf plusminus Thorn onequarter divide brokenbar degree
|
|
7374
|
-
thorn threequarters twosuperior registered minus eth multiply threesuperior
|
|
7375
|
-
copyright Aacute Acircumflex Adieresis Agrave Aring Atilde Ccedilla Eacute
|
|
7376
|
-
Ecircumflex Edieresis Egrave Iacute Icircumflex Idieresis Igrave Ntilde
|
|
7377
|
-
Oacute Ocircumflex Odieresis Ograve Otilde Scaron Uacute Ucircumflex
|
|
7378
|
-
Udieresis Ugrave Yacute Ydieresis Zcaron aacute acircumflex adieresis
|
|
7379
|
-
agrave aring atilde ccedilla eacute ecircumflex edieresis egrave iacute
|
|
7380
|
-
icircumflex idieresis igrave ntilde oacute ocircumflex odieresis ograve
|
|
7381
|
-
otilde scaron uacute ucircumflex udieresis ugrave yacute ydieresis zcaron
|
|
7382
|
-
`.trim().split(/\s+/);
|
|
7383
|
-
function glyphUnicode(name) {
|
|
7384
|
-
if (!name || name === ".notdef") return void 0;
|
|
7385
|
-
const known = GLYPH_UNICODE.get(name);
|
|
7386
|
-
if (known !== void 0) return known;
|
|
7387
|
-
const match = /^uni([0-9A-F]{4})$|^u([0-9A-F]{4,6})$/.exec(name);
|
|
7388
|
-
const hex2 = match?.[1] ?? match?.[2];
|
|
7389
|
-
if (!hex2) return void 0;
|
|
7390
|
-
const code = Number.parseInt(hex2, 16);
|
|
7391
|
-
const surrogate = code >= 55296 && code <= 57343;
|
|
7392
|
-
const nonCharacter = (code & 65534) === 65534;
|
|
7393
|
-
return code <= 1114111 && !surrogate && !nonCharacter ? code : void 0;
|
|
7413
|
+
var FONT_TRUETYPE = 1;
|
|
7414
|
+
var FALLBACK_FAMILY = "Noto Sans";
|
|
7415
|
+
function isStandardFamily(family) {
|
|
7416
|
+
return family.toLowerCase() in STANDARD_FAMILIES;
|
|
7394
7417
|
}
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7418
|
+
function standardFontName(family, bold, italic) {
|
|
7419
|
+
const variants = STANDARD_FAMILIES[family.toLowerCase()];
|
|
7420
|
+
if (!variants) return void 0;
|
|
7421
|
+
return variants[(bold ? 1 : 0) + (italic ? 2 : 0)];
|
|
7422
|
+
}
|
|
7423
|
+
function firstNonWinAnsi(text) {
|
|
7424
|
+
for (const character of text) {
|
|
7425
|
+
const code = character.codePointAt(0);
|
|
7426
|
+
if (code === 10) continue;
|
|
7427
|
+
if (code >= 32 && code <= 126 || code >= 160 && code <= 255 || WIN_ANSI_EXTRAS.has(code))
|
|
7428
|
+
continue;
|
|
7429
|
+
return character;
|
|
7430
|
+
}
|
|
7431
|
+
return void 0;
|
|
7432
|
+
}
|
|
7433
|
+
var FontLibrary = class {
|
|
7434
|
+
#registered = [];
|
|
7435
|
+
#fetch;
|
|
7436
|
+
#bytes = /* @__PURE__ */ new Map();
|
|
7437
|
+
#coverage = /* @__PURE__ */ new Map();
|
|
7438
|
+
/** Loaded PDFium font handles, keyed by document and font bytes. */
|
|
7439
|
+
#handles = /* @__PURE__ */ new Map();
|
|
7440
|
+
#fallbackUrl;
|
|
7441
|
+
#fallback;
|
|
7442
|
+
constructor(fetchBytes2) {
|
|
7443
|
+
this.#fetch = fetchBytes2;
|
|
7444
|
+
}
|
|
7445
|
+
setFallbackUrl(url) {
|
|
7446
|
+
this.#fallbackUrl = url;
|
|
7447
|
+
}
|
|
7448
|
+
register(fonts) {
|
|
7449
|
+
this.#registered.length = 0;
|
|
7450
|
+
this.#registered.push(...fonts);
|
|
7451
|
+
}
|
|
7452
|
+
/** Whether `family` names a registered font. */
|
|
7453
|
+
hasFamily(family) {
|
|
7454
|
+
return this.#registered.some((font) => sameFamily(font.family, family));
|
|
7455
|
+
}
|
|
7456
|
+
/**
|
|
7457
|
+
* Fetches whatever the given texts and families may need, so that
|
|
7458
|
+
* validation and drawing can run synchronously afterwards.
|
|
7459
|
+
*/
|
|
7460
|
+
async prepare(requests) {
|
|
7461
|
+
const families = new Set(
|
|
7462
|
+
requests.map((request) => request.family.toLowerCase())
|
|
7439
7463
|
);
|
|
7440
|
-
|
|
7464
|
+
const fonts = this.#registered.filter(
|
|
7465
|
+
(font) => families.has(font.family.toLowerCase())
|
|
7466
|
+
);
|
|
7467
|
+
for (const font of fonts) await this.#bytesOf(font);
|
|
7468
|
+
const needsFallback = requests.some(
|
|
7469
|
+
(request) => (
|
|
7470
|
+
// Text the standard fonts cannot encode, or a family only the
|
|
7471
|
+
// fallback can stand in for (an embedded font that lost a glyph).
|
|
7472
|
+
(firstNonWinAnsi(request.text) !== void 0 || !isStandardFamily(request.family) && !this.hasFamily(request.family)) && !this.#coveringRegistered({ ...request, bold: false, italic: false })
|
|
7473
|
+
)
|
|
7474
|
+
);
|
|
7475
|
+
if (needsFallback && !this.#fallback && this.#fallbackUrl)
|
|
7476
|
+
this.#fallback = await this.#fetch(this.#fallbackUrl);
|
|
7477
|
+
}
|
|
7478
|
+
/** Checks a request against what is loaded; `undefined` means it will resolve. */
|
|
7479
|
+
problem(request) {
|
|
7480
|
+
const standard = isStandardFamily(request.family);
|
|
7481
|
+
if (!standard && !this.hasFamily(request.family))
|
|
7441
7482
|
return {
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
widths: [],
|
|
7446
|
-
bbox: [xMin, yMin, xMax, yMax],
|
|
7447
|
-
unitsPerEm
|
|
7483
|
+
path: "/style/fontFamily",
|
|
7484
|
+
code: "unknown-font",
|
|
7485
|
+
message: `Unknown font family ${request.family}; Helvetica, Times, Courier and registered fonts are available`
|
|
7448
7486
|
};
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
);
|
|
7460
|
-
return custom.get(sid);
|
|
7487
|
+
if (standard && firstNonWinAnsi(request.text) === void 0)
|
|
7488
|
+
return void 0;
|
|
7489
|
+
if (this.#coveringRegistered(request)) return void 0;
|
|
7490
|
+
if (this.#fallback && this.#covers(this.#fallback, request.text))
|
|
7491
|
+
return void 0;
|
|
7492
|
+
const bad = this.#fallback ? this.#firstMissing(this.#fallback, request.text) : firstNonWinAnsi(request.text);
|
|
7493
|
+
return {
|
|
7494
|
+
path: "/text",
|
|
7495
|
+
code: "font-unavailable",
|
|
7496
|
+
message: bad ? `No available font can draw "${bad}" (U+${bad.codePointAt(0).toString(16).toUpperCase().padStart(4, "0")})` : "No available font can draw the text"
|
|
7461
7497
|
};
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7498
|
+
}
|
|
7499
|
+
/** The font to draw `request` with in `document`; `prepare` must have run. */
|
|
7500
|
+
resolve(pdfium, document2, request) {
|
|
7501
|
+
const { lib } = pdfium;
|
|
7502
|
+
if (isStandardFamily(request.family) && firstNonWinAnsi(request.text) === void 0) {
|
|
7503
|
+
const name = standardFontName(
|
|
7504
|
+
request.family,
|
|
7505
|
+
request.bold,
|
|
7506
|
+
request.italic
|
|
7507
|
+
);
|
|
7508
|
+
return {
|
|
7509
|
+
handle: lib.FPDFText_LoadStandardFont(document2, name),
|
|
7510
|
+
family: name
|
|
7511
|
+
};
|
|
7512
|
+
}
|
|
7513
|
+
const registered = this.#coveringRegistered(request);
|
|
7514
|
+
if (registered) {
|
|
7515
|
+
const exact = isBold(registered.font) === request.bold && isItalic(registered.font) === request.italic;
|
|
7516
|
+
return {
|
|
7517
|
+
handle: this.#load(pdfium, document2, registered.bytes),
|
|
7518
|
+
family: registered.font.family,
|
|
7519
|
+
...exact ? {} : {
|
|
7520
|
+
substitution: `${registered.font.family} has no matching bold or italic face`
|
|
7521
|
+
}
|
|
7522
|
+
};
|
|
7523
|
+
}
|
|
7524
|
+
if (!this.#fallback || !this.#covers(this.#fallback, request.text))
|
|
7525
|
+
throw new Error(`No font covers "${request.text}"`);
|
|
7526
|
+
return {
|
|
7527
|
+
handle: this.#load(pdfium, document2, this.#fallback),
|
|
7528
|
+
family: FALLBACK_FAMILY,
|
|
7529
|
+
substitution: `${request.family} cannot draw this text; ${FALLBACK_FAMILY} is used`
|
|
7478
7530
|
};
|
|
7479
|
-
|
|
7480
|
-
|
|
7531
|
+
}
|
|
7532
|
+
/** Closes the fonts loaded into a document that is going away. */
|
|
7533
|
+
release(pdfium, document2) {
|
|
7534
|
+
const handles = this.#handles.get(document2);
|
|
7535
|
+
if (!handles) return;
|
|
7536
|
+
for (const handle of handles.values()) pdfium.lib.FPDFFont_Close(handle);
|
|
7537
|
+
this.#handles.delete(document2);
|
|
7538
|
+
}
|
|
7539
|
+
covers(bytes2, text) {
|
|
7540
|
+
return this.#covers(bytes2, text);
|
|
7541
|
+
}
|
|
7542
|
+
#coveringRegistered(request) {
|
|
7543
|
+
const candidates = this.#registered.filter((font) => sameFamily(font.family, request.family)).map((font) => ({ font, bytes: this.#loadedBytes(font) })).filter(
|
|
7544
|
+
(entry) => entry.bytes !== void 0 && this.#covers(entry.bytes, request.text)
|
|
7481
7545
|
);
|
|
7546
|
+
const score = (font) => (isBold(font) === request.bold ? 2 : 0) + (isItalic(font) === request.italic ? 1 : 0);
|
|
7547
|
+
return candidates.sort((a, b) => score(b.font) - score(a.font))[0];
|
|
7548
|
+
}
|
|
7549
|
+
#covers(bytes2, text) {
|
|
7550
|
+
return this.#firstMissing(bytes2, text) === void 0;
|
|
7551
|
+
}
|
|
7552
|
+
/** The first character of `text` the font has no glyph for; layout handles line breaks and spaces. */
|
|
7553
|
+
#firstMissing(bytes2, text) {
|
|
7554
|
+
let coverage = this.#coverage.get(bytes2);
|
|
7555
|
+
if (!coverage) {
|
|
7556
|
+
coverage = parseCmap(bytes2);
|
|
7557
|
+
this.#coverage.set(bytes2, coverage);
|
|
7558
|
+
}
|
|
7559
|
+
for (const character of text) {
|
|
7560
|
+
const code = character.codePointAt(0);
|
|
7561
|
+
if (code === 10 || code === 32) continue;
|
|
7562
|
+
if (!coverage.has(code)) return character;
|
|
7563
|
+
}
|
|
7564
|
+
return void 0;
|
|
7565
|
+
}
|
|
7566
|
+
#load(pdfium, document2, bytes2) {
|
|
7567
|
+
let handles = this.#handles.get(document2);
|
|
7568
|
+
if (!handles) {
|
|
7569
|
+
handles = /* @__PURE__ */ new Map();
|
|
7570
|
+
this.#handles.set(document2, handles);
|
|
7571
|
+
}
|
|
7572
|
+
let handle = handles.get(bytes2);
|
|
7573
|
+
if (handle === void 0) {
|
|
7574
|
+
const pointer = pdfium.writeBytes(bytes2);
|
|
7575
|
+
try {
|
|
7576
|
+
handle = pdfium.lib.FPDFText_LoadFont(
|
|
7577
|
+
document2,
|
|
7578
|
+
pointer,
|
|
7579
|
+
bytes2.byteLength,
|
|
7580
|
+
FONT_TRUETYPE,
|
|
7581
|
+
true
|
|
7582
|
+
);
|
|
7583
|
+
} finally {
|
|
7584
|
+
pdfium.free(pointer);
|
|
7585
|
+
}
|
|
7586
|
+
if (!handle) throw new Error("PDFium could not load the font");
|
|
7587
|
+
handles.set(bytes2, handle);
|
|
7588
|
+
}
|
|
7589
|
+
return handle;
|
|
7590
|
+
}
|
|
7591
|
+
#loadedBytes(font) {
|
|
7592
|
+
return typeof font.source === "string" ? this.#bytes.get(font.source) : this.#bytes.get(sourceKey(font)) ?? new Uint8Array(font.source);
|
|
7593
|
+
}
|
|
7594
|
+
async #bytesOf(font) {
|
|
7595
|
+
const key = sourceKey(font);
|
|
7596
|
+
let bytes2 = this.#bytes.get(key);
|
|
7597
|
+
if (!bytes2) {
|
|
7598
|
+
bytes2 = typeof font.source === "string" ? await this.#fetch(font.source) : new Uint8Array(font.source);
|
|
7599
|
+
this.#bytes.set(key, bytes2);
|
|
7600
|
+
}
|
|
7601
|
+
return bytes2;
|
|
7602
|
+
}
|
|
7603
|
+
};
|
|
7604
|
+
function sourceKey(font) {
|
|
7605
|
+
return typeof font.source === "string" ? font.source : `${font.family}:${font.weight}:${font.style}:${font.source.byteLength}`;
|
|
7606
|
+
}
|
|
7607
|
+
function sameFamily(a, b) {
|
|
7608
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
7609
|
+
}
|
|
7610
|
+
function isBold(font) {
|
|
7611
|
+
return font.weight >= 600;
|
|
7612
|
+
}
|
|
7613
|
+
function isItalic(font) {
|
|
7614
|
+
return font.style !== "normal";
|
|
7615
|
+
}
|
|
7616
|
+
function glyphOutlines(view, tables) {
|
|
7617
|
+
const head2 = tables.get("head");
|
|
7618
|
+
const maxp = tables.get("maxp");
|
|
7619
|
+
const loca = tables.get("loca");
|
|
7620
|
+
if (!head2 || !maxp || !loca || !tables.has("glyf")) return void 0;
|
|
7621
|
+
const longOffsets = view.getInt16(head2.offset + 50) === 1;
|
|
7622
|
+
const count = view.getUint16(maxp.offset + 4);
|
|
7623
|
+
return (glyph) => {
|
|
7624
|
+
if (glyph < 0 || glyph >= count) return false;
|
|
7625
|
+
const at = loca.offset + glyph * (longOffsets ? 4 : 2);
|
|
7626
|
+
const start = longOffsets ? view.getUint32(at) : view.getUint16(at) * 2;
|
|
7627
|
+
const end = longOffsets ? view.getUint32(at + 4) : view.getUint16(at + 2) * 2;
|
|
7628
|
+
return end > start;
|
|
7629
|
+
};
|
|
7630
|
+
}
|
|
7631
|
+
function parseCmap(bytes2) {
|
|
7632
|
+
const view = new DataView(bytes2.buffer, bytes2.byteOffset, bytes2.byteLength);
|
|
7633
|
+
const ranges = [];
|
|
7634
|
+
const glyphs = /* @__PURE__ */ new Map();
|
|
7635
|
+
let outlines;
|
|
7636
|
+
try {
|
|
7637
|
+
const tables = view.getUint16(4);
|
|
7638
|
+
let cmapOffset = -1;
|
|
7639
|
+
const offsets = /* @__PURE__ */ new Map();
|
|
7640
|
+
for (let index = 0; index < tables; index += 1) {
|
|
7641
|
+
const record = 12 + index * 16;
|
|
7642
|
+
const tag = String.fromCharCode(
|
|
7643
|
+
bytes2[record],
|
|
7644
|
+
bytes2[record + 1],
|
|
7645
|
+
bytes2[record + 2],
|
|
7646
|
+
bytes2[record + 3]
|
|
7647
|
+
);
|
|
7648
|
+
offsets.set(tag, {
|
|
7649
|
+
offset: view.getUint32(record + 8),
|
|
7650
|
+
length: view.getUint32(record + 12)
|
|
7651
|
+
});
|
|
7652
|
+
if (tag === "cmap") cmapOffset = view.getUint32(record + 8);
|
|
7653
|
+
}
|
|
7654
|
+
outlines = glyphOutlines(view, offsets);
|
|
7655
|
+
if (cmapOffset < 0)
|
|
7656
|
+
return {
|
|
7657
|
+
has: () => false,
|
|
7658
|
+
drawable: () => false,
|
|
7659
|
+
glyph: () => void 0
|
|
7660
|
+
};
|
|
7661
|
+
const subtables = view.getUint16(cmapOffset + 2);
|
|
7662
|
+
let best;
|
|
7663
|
+
for (let index = 0; index < subtables; index += 1) {
|
|
7664
|
+
const record = cmapOffset + 4 + index * 8;
|
|
7665
|
+
const platform = view.getUint16(record);
|
|
7666
|
+
const encoding = view.getUint16(record + 2);
|
|
7667
|
+
const offset2 = cmapOffset + view.getUint32(record + 4);
|
|
7668
|
+
const format = view.getUint16(offset2);
|
|
7669
|
+
const unicode = platform === 0 || platform === 3 && (encoding === 1 || encoding === 10);
|
|
7670
|
+
if (!unicode || format !== 4 && format !== 12) continue;
|
|
7671
|
+
if (!best || format > best.format) best = { offset: offset2, format };
|
|
7672
|
+
}
|
|
7673
|
+
if (!best)
|
|
7674
|
+
return {
|
|
7675
|
+
has: () => false,
|
|
7676
|
+
drawable: () => false,
|
|
7677
|
+
glyph: () => void 0
|
|
7678
|
+
};
|
|
7679
|
+
if (best.format === 12) {
|
|
7680
|
+
const groups = view.getUint32(best.offset + 12);
|
|
7681
|
+
for (let index = 0; index < groups; index += 1) {
|
|
7682
|
+
const group = best.offset + 16 + index * 12;
|
|
7683
|
+
const start = view.getUint32(group);
|
|
7684
|
+
const end = view.getUint32(group + 4);
|
|
7685
|
+
const startGlyph = view.getUint32(group + 8);
|
|
7686
|
+
ranges.push([start, end]);
|
|
7687
|
+
for (let code = start; code <= end && code - start < 65536; code += 1)
|
|
7688
|
+
glyphs.set(code, startGlyph + (code - start));
|
|
7689
|
+
}
|
|
7690
|
+
} else {
|
|
7691
|
+
const segments = view.getUint16(best.offset + 6) / 2;
|
|
7692
|
+
const ends = best.offset + 14;
|
|
7693
|
+
const starts = ends + segments * 2 + 2;
|
|
7694
|
+
const deltas = starts + segments * 2;
|
|
7695
|
+
const rangeOffsets = deltas + segments * 2;
|
|
7696
|
+
for (let index = 0; index < segments; index += 1) {
|
|
7697
|
+
const end = view.getUint16(ends + index * 2);
|
|
7698
|
+
const start = view.getUint16(starts + index * 2);
|
|
7699
|
+
if (start === 65535) continue;
|
|
7700
|
+
ranges.push([start, end]);
|
|
7701
|
+
const delta = view.getInt16(deltas + index * 2);
|
|
7702
|
+
const rangeOffset = view.getUint16(rangeOffsets + index * 2);
|
|
7703
|
+
for (let code = start; code <= end; code += 1) {
|
|
7704
|
+
let glyph;
|
|
7705
|
+
if (rangeOffset === 0) glyph = code + delta & 65535;
|
|
7706
|
+
else {
|
|
7707
|
+
const at = rangeOffsets + index * 2 + rangeOffset + (code - start) * 2;
|
|
7708
|
+
const raw = view.getUint16(at);
|
|
7709
|
+
glyph = raw === 0 ? 0 : raw + delta & 65535;
|
|
7710
|
+
}
|
|
7711
|
+
glyphs.set(code, glyph);
|
|
7712
|
+
}
|
|
7713
|
+
}
|
|
7714
|
+
}
|
|
7715
|
+
} catch {
|
|
7716
|
+
return { has: () => false, drawable: () => false, glyph: () => void 0 };
|
|
7717
|
+
}
|
|
7718
|
+
ranges.sort((a, b) => a[0] - b[0]);
|
|
7719
|
+
return {
|
|
7720
|
+
glyph(codePoint) {
|
|
7721
|
+
return glyphs.get(codePoint);
|
|
7722
|
+
},
|
|
7723
|
+
drawable(codePoint) {
|
|
7724
|
+
const glyph = glyphs.get(codePoint);
|
|
7725
|
+
if (glyph === void 0 || glyph === 0) return false;
|
|
7726
|
+
return outlines ? outlines(glyph) : true;
|
|
7727
|
+
},
|
|
7728
|
+
has(codePoint) {
|
|
7729
|
+
let low = 0;
|
|
7730
|
+
let high = ranges.length - 1;
|
|
7731
|
+
while (low <= high) {
|
|
7732
|
+
const middle = low + high >> 1;
|
|
7733
|
+
const [start, end] = ranges[middle];
|
|
7734
|
+
if (codePoint < start) high = middle - 1;
|
|
7735
|
+
else if (codePoint > end) low = middle + 1;
|
|
7736
|
+
else return true;
|
|
7737
|
+
}
|
|
7738
|
+
return false;
|
|
7739
|
+
}
|
|
7740
|
+
};
|
|
7741
|
+
}
|
|
7742
|
+
var TextMeasurer = class {
|
|
7743
|
+
#pdfium;
|
|
7744
|
+
#document;
|
|
7745
|
+
#advances = /* @__PURE__ */ new Map();
|
|
7746
|
+
#metrics = /* @__PURE__ */ new Map();
|
|
7747
|
+
constructor(pdfium, document2) {
|
|
7748
|
+
this.#pdfium = pdfium;
|
|
7749
|
+
this.#document = document2;
|
|
7750
|
+
}
|
|
7751
|
+
/** Width of `text` in points at `fontSize`, without kerning. */
|
|
7752
|
+
advance(font, fontSize, text) {
|
|
7753
|
+
let total = 0;
|
|
7754
|
+
for (const character of text) total += this.#advanceOf(font, character);
|
|
7755
|
+
return total * fontSize / 1e3;
|
|
7756
|
+
}
|
|
7757
|
+
/** Ascent above and descent below the baseline, in points, both positive. */
|
|
7758
|
+
metrics(font, fontSize) {
|
|
7759
|
+
let unit = this.#metrics.get(font);
|
|
7760
|
+
if (!unit) {
|
|
7761
|
+
const { lib } = this.#pdfium;
|
|
7762
|
+
const ascent = this.#pdfium.readNumbers(
|
|
7763
|
+
1,
|
|
7764
|
+
"float",
|
|
7765
|
+
([pointer]) => lib.FPDFFont_GetAscent(font, 1e3, pointer)
|
|
7766
|
+
)?.[0] ?? 750;
|
|
7767
|
+
const descent = this.#pdfium.readNumbers(
|
|
7768
|
+
1,
|
|
7769
|
+
"float",
|
|
7770
|
+
([pointer]) => lib.FPDFFont_GetDescent(font, 1e3, pointer)
|
|
7771
|
+
)?.[0] ?? -250;
|
|
7772
|
+
unit = { ascent, descent: Math.abs(descent) };
|
|
7773
|
+
this.#metrics.set(font, unit);
|
|
7774
|
+
}
|
|
7482
7775
|
return {
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
glyphNames,
|
|
7486
|
-
widths,
|
|
7487
|
-
bbox: [xMin, yMin, xMax, yMax],
|
|
7488
|
-
unitsPerEm
|
|
7776
|
+
ascent: unit.ascent * fontSize / 1e3,
|
|
7777
|
+
descent: unit.descent * fontSize / 1e3
|
|
7489
7778
|
};
|
|
7490
|
-
} catch (error) {
|
|
7491
|
-
if (error instanceof RangeError) return void 0;
|
|
7492
|
-
throw error;
|
|
7493
7779
|
}
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
throw new RangeError("Outside the font");
|
|
7500
|
-
return bytes2[offset2];
|
|
7501
|
-
};
|
|
7502
|
-
const u162 = (offset2) => at(offset2) << 8 | at(offset2 + 1);
|
|
7503
|
-
const names2 = readIndex(bytes2, at(2), at, u162);
|
|
7504
|
-
const [start, end] = names2.items[0] ?? [0, 0];
|
|
7505
|
-
if (names2.items.length !== 1 || end - start > 127) return void 0;
|
|
7506
|
-
const safe = bytes2.slice();
|
|
7507
|
-
for (let offset2 = start; offset2 < end; offset2 += 1) {
|
|
7508
|
-
const byte = safe[offset2];
|
|
7509
|
-
if (offset2 === start && byte === 0) continue;
|
|
7510
|
-
if (byte < 33 || byte > 126 || UNSAFE_NAME_BYTES.has(byte))
|
|
7511
|
-
safe[offset2] = 95;
|
|
7780
|
+
#advanceOf(font, character) {
|
|
7781
|
+
let cache = this.#advances.get(font);
|
|
7782
|
+
if (!cache) {
|
|
7783
|
+
cache = /* @__PURE__ */ new Map();
|
|
7784
|
+
this.#advances.set(font, cache);
|
|
7512
7785
|
}
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
var UNSAFE_NAME_BYTES = new Set(
|
|
7520
|
-
[..."[](){}<>/%"].map((character) => character.charCodeAt(0))
|
|
7521
|
-
);
|
|
7522
|
-
function readIndex(bytes2, start, at, u162) {
|
|
7523
|
-
const count = u162(start);
|
|
7524
|
-
if (count === 0) return { items: [], end: start + 2 };
|
|
7525
|
-
const offSize = at(start + 2);
|
|
7526
|
-
if (offSize < 1 || offSize > 4) throw new RangeError("Bad offset size");
|
|
7527
|
-
const offset2 = (index) => {
|
|
7528
|
-
let value = 0;
|
|
7529
|
-
for (let byte = 0; byte < offSize; byte += 1)
|
|
7530
|
-
value = value * 256 + at(start + 3 + index * offSize + byte);
|
|
7531
|
-
return value;
|
|
7532
|
-
};
|
|
7533
|
-
if (offset2(0) !== 1) throw new RangeError("Bad INDEX");
|
|
7534
|
-
const base = start + 2 + (count + 1) * offSize;
|
|
7535
|
-
const items = [];
|
|
7536
|
-
for (let index = 0; index < count; index += 1) {
|
|
7537
|
-
const from = base + offset2(index);
|
|
7538
|
-
const to = base + offset2(index + 1);
|
|
7539
|
-
if (to < from || to > bytes2.length) throw new RangeError("Bad INDEX");
|
|
7540
|
-
items.push([from, to]);
|
|
7786
|
+
let advance2 = cache.get(character);
|
|
7787
|
+
if (advance2 === void 0) {
|
|
7788
|
+
advance2 = this.#inkWidth(font, `H${character}H`) - this.#inkWidth(font, "HH");
|
|
7789
|
+
cache.set(character, advance2);
|
|
7790
|
+
}
|
|
7791
|
+
return advance2;
|
|
7541
7792
|
}
|
|
7542
|
-
|
|
7543
|
-
}
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
if (byte <= 21) {
|
|
7552
|
-
const operator = byte === 12 ? 1200 + at(offset2 + 1) : byte;
|
|
7553
|
-
offset2 += byte === 12 ? 2 : 1;
|
|
7554
|
-
entries.set(operator, operands);
|
|
7555
|
-
operands = [];
|
|
7556
|
-
} else if (byte === 28) {
|
|
7557
|
-
operands.push(int16(at(offset2 + 1) << 8 | at(offset2 + 2)));
|
|
7558
|
-
offset2 += 3;
|
|
7559
|
-
} else if (byte === 29) {
|
|
7560
|
-
operands.push(
|
|
7561
|
-
at(offset2 + 1) << 24 | at(offset2 + 2) << 16 | at(offset2 + 3) << 8 | at(offset2 + 4)
|
|
7562
|
-
);
|
|
7563
|
-
offset2 += 5;
|
|
7564
|
-
} else if (byte === 30) {
|
|
7565
|
-
let text = "";
|
|
7566
|
-
offset2 += 1;
|
|
7567
|
-
for (let done = false; !done; offset2 += 1) {
|
|
7568
|
-
const pair = at(offset2);
|
|
7569
|
-
for (const nibble of [pair >> 4, pair & 15]) {
|
|
7570
|
-
if (nibble === 15) {
|
|
7571
|
-
done = true;
|
|
7572
|
-
break;
|
|
7573
|
-
}
|
|
7574
|
-
text += REAL_NIBBLES[nibble] ?? "";
|
|
7575
|
-
}
|
|
7793
|
+
#inkWidth(font, text) {
|
|
7794
|
+
const { lib } = this.#pdfium;
|
|
7795
|
+
const object = lib.FPDFPageObj_CreateTextObj(this.#document, font, 1e3);
|
|
7796
|
+
try {
|
|
7797
|
+
const wide = this.#pdfium.writeWideString(text);
|
|
7798
|
+
try {
|
|
7799
|
+
lib.FPDFText_SetText(object, wide);
|
|
7800
|
+
} finally {
|
|
7801
|
+
this.#pdfium.free(wide);
|
|
7576
7802
|
}
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
offset2 += 2;
|
|
7587
|
-
} else throw new RangeError("Bad DICT byte");
|
|
7803
|
+
const bounds = this.#pdfium.readNumbers(
|
|
7804
|
+
4,
|
|
7805
|
+
"float",
|
|
7806
|
+
([l, b, r, t]) => lib.FPDFPageObj_GetBounds(object, l, b, r, t)
|
|
7807
|
+
);
|
|
7808
|
+
return bounds ? bounds[2] - bounds[0] : 0;
|
|
7809
|
+
} finally {
|
|
7810
|
+
lib.FPDFPageObj_Destroy(object);
|
|
7811
|
+
}
|
|
7588
7812
|
}
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
"5",
|
|
7598
|
-
"6",
|
|
7599
|
-
"7",
|
|
7600
|
-
"8",
|
|
7601
|
-
"9",
|
|
7602
|
-
".",
|
|
7603
|
-
"E",
|
|
7604
|
-
"E-",
|
|
7605
|
-
"",
|
|
7606
|
-
"-"
|
|
7607
|
-
];
|
|
7608
|
-
function charsetNames(offset2, glyphCount, stringOf, at, u162) {
|
|
7609
|
-
const names2 = [".notdef"];
|
|
7610
|
-
if (offset2 === 0) {
|
|
7611
|
-
for (let glyph = 1; glyph < glyphCount; glyph += 1)
|
|
7612
|
-
names2.push(stringOf(glyph));
|
|
7613
|
-
return names2;
|
|
7813
|
+
};
|
|
7814
|
+
function fontCanDraw(pdfium, font, text) {
|
|
7815
|
+
const { lib } = pdfium;
|
|
7816
|
+
if (!lib.FPDFFont_GetIsEmbedded(font)) {
|
|
7817
|
+
const base = pdfium.readUtf8String(
|
|
7818
|
+
(buffer, bytes2) => lib.FPDFFont_GetBaseFontName(font, buffer, bytes2)
|
|
7819
|
+
);
|
|
7820
|
+
return isStandardFamily(base.split(/[-,]/)[0] ?? "") && firstNonWinAnsi(text) === void 0;
|
|
7614
7821
|
}
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
}
|
|
7622
|
-
while (names2.length < glyphCount) {
|
|
7623
|
-
const first = u162(cursor);
|
|
7624
|
-
const left = format === 1 ? at(cursor + 2) : u162(cursor + 2);
|
|
7625
|
-
cursor += format === 1 ? 3 : 4;
|
|
7626
|
-
for (let step = 0; step <= left && names2.length < glyphCount; step += 1)
|
|
7627
|
-
names2.push(stringOf(first + step));
|
|
7628
|
-
}
|
|
7629
|
-
} else throw new RangeError("Bad charset format");
|
|
7630
|
-
return names2;
|
|
7822
|
+
const coverage = fontCoverage(pdfium, font);
|
|
7823
|
+
if (!coverage) return false;
|
|
7824
|
+
return [...text].every((character) => {
|
|
7825
|
+
const code = character.codePointAt(0);
|
|
7826
|
+
if (code === 32) return (coverage.glyph(code) ?? 0) !== 0;
|
|
7827
|
+
return code === 10 || coverage.drawable(code);
|
|
7828
|
+
});
|
|
7631
7829
|
}
|
|
7632
|
-
function
|
|
7633
|
-
const
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7830
|
+
function fontCanRewrite(pdfium, font, text) {
|
|
7831
|
+
const characters = [...text].filter((character) => character !== "\n");
|
|
7832
|
+
if (!characters.every(
|
|
7833
|
+
(character) => advance(pdfium, font, character.codePointAt(0)) > 0
|
|
7834
|
+
))
|
|
7835
|
+
return false;
|
|
7836
|
+
if (fontCanDraw(pdfium, font, text)) return true;
|
|
7837
|
+
if (!pdfium.lib.FPDFFont_GetIsEmbedded(font)) return false;
|
|
7838
|
+
const data = fontBytes(pdfium, font);
|
|
7839
|
+
const coverage = data && cffCoverage(data);
|
|
7840
|
+
if (!coverage) return false;
|
|
7841
|
+
return characters.every(
|
|
7842
|
+
(character) => coverage.has(character.codePointAt(0))
|
|
7843
|
+
);
|
|
7844
|
+
}
|
|
7845
|
+
function advance(pdfium, font, code) {
|
|
7846
|
+
if (code > 65535) return 0;
|
|
7847
|
+
return pdfium.readNumbers(
|
|
7848
|
+
1,
|
|
7849
|
+
"float",
|
|
7850
|
+
([width]) => pdfium.lib.FPDFFont_GetGlyphWidth(font, code, 1e3, width)
|
|
7851
|
+
)?.[0] ?? 0;
|
|
7852
|
+
}
|
|
7853
|
+
function cffCoverage(data) {
|
|
7854
|
+
const cff = readCff(data);
|
|
7855
|
+
if (!cff || cff.cid) return void 0;
|
|
7856
|
+
const glyphs = /* @__PURE__ */ new Map();
|
|
7857
|
+
cff.glyphNames.forEach((name, glyph) => {
|
|
7858
|
+
const code = glyphUnicode(name);
|
|
7859
|
+
if (glyph !== 0 && code !== void 0 && !glyphs.has(code))
|
|
7860
|
+
glyphs.set(code, glyph);
|
|
7861
|
+
});
|
|
7862
|
+
return {
|
|
7863
|
+
has: (code) => glyphs.has(code),
|
|
7864
|
+
glyph: (code) => glyphs.get(code),
|
|
7865
|
+
drawable: (code) => glyphs.has(code)
|
|
7866
|
+
};
|
|
7867
|
+
}
|
|
7868
|
+
function fontCoverage(pdfium, font) {
|
|
7869
|
+
const data = fontBytes(pdfium, font);
|
|
7870
|
+
if (!data) return void 0;
|
|
7871
|
+
const tag = String.fromCharCode(...data.slice(0, 4));
|
|
7872
|
+
const truetype = data[0] === 0 && data[1] === 1 && data[2] === 0 && data[3] === 0 || tag === "true";
|
|
7873
|
+
return truetype ? parseCmap(data) : void 0;
|
|
7874
|
+
}
|
|
7875
|
+
function fontBytes(pdfium, font) {
|
|
7876
|
+
const { lib } = pdfium;
|
|
7877
|
+
const size = pdfium.readNumbers(
|
|
7878
|
+
1,
|
|
7879
|
+
"i32",
|
|
7880
|
+
([out]) => lib.FPDFFont_GetFontData(font, 0, 0, out)
|
|
7881
|
+
)?.[0];
|
|
7882
|
+
if (!size) return void 0;
|
|
7883
|
+
const buffer = pdfium.malloc(size);
|
|
7884
|
+
try {
|
|
7885
|
+
const out = pdfium.malloc(4);
|
|
7886
|
+
try {
|
|
7887
|
+
if (!lib.FPDFFont_GetFontData(font, buffer, size, out)) return void 0;
|
|
7888
|
+
} finally {
|
|
7889
|
+
pdfium.free(out);
|
|
7666
7890
|
}
|
|
7667
|
-
return
|
|
7668
|
-
}
|
|
7669
|
-
|
|
7670
|
-
}
|
|
7671
|
-
function subrBias(count) {
|
|
7672
|
-
return count < 1240 ? 107 : count < 33900 ? 1131 : 32768;
|
|
7673
|
-
}
|
|
7674
|
-
var STACK_CLEARING = {
|
|
7675
|
-
1: "pairs",
|
|
7676
|
-
// hstem
|
|
7677
|
-
3: "pairs",
|
|
7678
|
-
// vstem
|
|
7679
|
-
18: "pairs",
|
|
7680
|
-
// hstemhm
|
|
7681
|
-
23: "pairs",
|
|
7682
|
-
// vstemhm
|
|
7683
|
-
19: "pairs",
|
|
7684
|
-
// hintmask, after implied vstems
|
|
7685
|
-
20: "pairs",
|
|
7686
|
-
// cntrmask
|
|
7687
|
-
21: 2,
|
|
7688
|
-
// rmoveto
|
|
7689
|
-
22: 1,
|
|
7690
|
-
// hmoveto
|
|
7691
|
-
4: 1,
|
|
7692
|
-
// vmoveto
|
|
7693
|
-
14: "endchar"
|
|
7694
|
-
// endchar: none, or four for an accented character
|
|
7695
|
-
};
|
|
7696
|
-
function int16(value) {
|
|
7697
|
-
return value >= 32768 ? value - 65536 : value;
|
|
7891
|
+
return pdfium.readBytes(buffer, size);
|
|
7892
|
+
} finally {
|
|
7893
|
+
pdfium.free(buffer);
|
|
7894
|
+
}
|
|
7698
7895
|
}
|
|
7699
|
-
function
|
|
7700
|
-
|
|
7896
|
+
function validateScript(text, issue) {
|
|
7897
|
+
for (const character of text) {
|
|
7898
|
+
const code = character.codePointAt(0);
|
|
7899
|
+
if (code >= 1424 && code <= 2303 || code >= 64285 && code <= 65023 || code >= 65136 && code <= 65279) {
|
|
7900
|
+
issue(
|
|
7901
|
+
"/text",
|
|
7902
|
+
"unsupported-script",
|
|
7903
|
+
`Right-to-left text such as "${character}" cannot be edited yet`
|
|
7904
|
+
);
|
|
7905
|
+
return false;
|
|
7906
|
+
}
|
|
7907
|
+
}
|
|
7908
|
+
return true;
|
|
7701
7909
|
}
|
|
7702
7910
|
|
|
7703
7911
|
// src/edit/pdf/engine/opentype.ts
|
|
@@ -8088,7 +8296,7 @@ function textFaceOf(pdfium, object, cache) {
|
|
|
8088
8296
|
);
|
|
8089
8297
|
if (!lib.FPDFFont_GetIsEmbedded(font))
|
|
8090
8298
|
return { key: `name:${baseName}`, family, missing: "not-embedded" };
|
|
8091
|
-
const program =
|
|
8299
|
+
const program = fontBytes(pdfium, font);
|
|
8092
8300
|
if (!program)
|
|
8093
8301
|
return { key: `embedded:${baseName}`, family, missing: "unreadable" };
|
|
8094
8302
|
const key = `${baseName}#${fnv1a(program).toString(16)}`;
|
|
@@ -8118,23 +8326,6 @@ function faceOf(program, baseName) {
|
|
|
8118
8326
|
const data = cffOpenType(program, cff, unicode);
|
|
8119
8327
|
return data ? { face: { data, format: "opentype" } } : { missing: "no-unicode" };
|
|
8120
8328
|
}
|
|
8121
|
-
function fontProgram(pdfium, font) {
|
|
8122
|
-
const { lib } = pdfium;
|
|
8123
|
-
const size = pdfium.readNumbers(
|
|
8124
|
-
1,
|
|
8125
|
-
"i32",
|
|
8126
|
-
([out2]) => lib.FPDFFont_GetFontData(font, 0, 0, out2)
|
|
8127
|
-
)?.[0];
|
|
8128
|
-
if (!size) return void 0;
|
|
8129
|
-
const buffer = pdfium.malloc(size);
|
|
8130
|
-
const out = pdfium.malloc(4);
|
|
8131
|
-
try {
|
|
8132
|
-
return lib.FPDFFont_GetFontData(font, buffer, size, out) ? pdfium.readBytes(buffer, size) : void 0;
|
|
8133
|
-
} finally {
|
|
8134
|
-
pdfium.free(out);
|
|
8135
|
-
pdfium.free(buffer);
|
|
8136
|
-
}
|
|
8137
|
-
}
|
|
8138
8329
|
function fnv1a(bytes2) {
|
|
8139
8330
|
let hash = 2166136261;
|
|
8140
8331
|
for (const byte of bytes2) hash = Math.imul(hash ^ byte, 16777619);
|
|
@@ -8474,7 +8665,7 @@ function resolveTableStyle(style) {
|
|
|
8474
8665
|
headerFill: style.headerFill ?? null
|
|
8475
8666
|
};
|
|
8476
8667
|
}
|
|
8477
|
-
function layoutTable(spec, ascent,
|
|
8668
|
+
function layoutTable(spec, ascent, advance2) {
|
|
8478
8669
|
const { cellPadding, fontSize } = spec.style;
|
|
8479
8670
|
const columns = [];
|
|
8480
8671
|
let x = spec.at.x;
|
|
@@ -8494,7 +8685,7 @@ function layoutTable(spec, ascent, advance) {
|
|
|
8494
8685
|
lineHeight: LINE_HEIGHT,
|
|
8495
8686
|
align: "left",
|
|
8496
8687
|
ascent,
|
|
8497
|
-
advance
|
|
8688
|
+
advance: advance2
|
|
8498
8689
|
})
|
|
8499
8690
|
);
|
|
8500
8691
|
const height = Math.max(...layouts.map((layout) => layout.height)) + 2 * cellPadding;
|
|
@@ -8698,9 +8889,9 @@ function removeObjects(context, location) {
|
|
|
8698
8889
|
const object = lib.FPDFPage_GetObject(page, index);
|
|
8699
8890
|
lib.FPDFPage_RemoveObject(page, object);
|
|
8700
8891
|
lib.FPDFPageObj_Destroy(object);
|
|
8892
|
+
context.spliceObjects(location.pageIndex, index, 1, []);
|
|
8701
8893
|
}
|
|
8702
8894
|
});
|
|
8703
|
-
context.spliceObjects(location.pageIndex, first, location.indexes.length, []);
|
|
8704
8895
|
return first;
|
|
8705
8896
|
}
|
|
8706
8897
|
function textBoxTarget(target, context, issue = () => {
|
|
@@ -8761,6 +8952,7 @@ function fontRequestsOf(operations, markOf, elementOf) {
|
|
|
8761
8952
|
text: operation2.text
|
|
8762
8953
|
});
|
|
8763
8954
|
break;
|
|
8955
|
+
case "replaceParagraphText":
|
|
8764
8956
|
case "replaceText": {
|
|
8765
8957
|
const box = spec(operation2.target);
|
|
8766
8958
|
if (box) {
|
|
@@ -8768,14 +8960,20 @@ function fontRequestsOf(operations, markOf, elementOf) {
|
|
|
8768
8960
|
break;
|
|
8769
8961
|
}
|
|
8770
8962
|
const element = elementOf(operation2.target);
|
|
8771
|
-
if (element?.kind === "text")
|
|
8963
|
+
if (element?.kind === "text" || element?.kind === "paragraph")
|
|
8772
8964
|
requests.push({
|
|
8773
8965
|
family: element.textStyle?.fontFamily ?? "Helvetica",
|
|
8774
|
-
text: operation2.text
|
|
8966
|
+
text: element.kind === "paragraph" && operation2.range ? (element.text ?? "").slice(0, operation2.range.start.offset) + operation2.text + (element.text ?? "").slice(operation2.range.end.offset) : operation2.text
|
|
8775
8967
|
});
|
|
8776
8968
|
break;
|
|
8777
8969
|
}
|
|
8778
8970
|
case "setTextStyle": {
|
|
8971
|
+
const paragraph = elementOf(operation2.target);
|
|
8972
|
+
if (paragraph?.kind === "paragraph" && operation2.style.fontSize !== void 0 && operation2.style.fontSize !== paragraph.textStyle?.fontSize)
|
|
8973
|
+
requests.push({
|
|
8974
|
+
family: paragraph.textStyle?.fontFamily ?? "Helvetica",
|
|
8975
|
+
text: paragraph.text ?? ""
|
|
8976
|
+
});
|
|
8779
8977
|
const box = spec(operation2.target);
|
|
8780
8978
|
if (box)
|
|
8781
8979
|
requests.push({
|
|
@@ -8813,83 +9011,826 @@ ${operation2.text}`
|
|
|
8813
9011
|
});
|
|
8814
9012
|
break;
|
|
8815
9013
|
}
|
|
8816
|
-
default:
|
|
8817
|
-
break;
|
|
9014
|
+
default:
|
|
9015
|
+
break;
|
|
9016
|
+
}
|
|
9017
|
+
}
|
|
9018
|
+
return requests;
|
|
9019
|
+
}
|
|
9020
|
+
function fontRequest(style, text) {
|
|
9021
|
+
return {
|
|
9022
|
+
family: style.fontFamily,
|
|
9023
|
+
bold: style.bold,
|
|
9024
|
+
italic: style.italic,
|
|
9025
|
+
text
|
|
9026
|
+
};
|
|
9027
|
+
}
|
|
9028
|
+
function validateFont(request, context, issue) {
|
|
9029
|
+
const problem = context.fonts.problem(request);
|
|
9030
|
+
if (problem) issue(problem.path, problem.code, problem.message);
|
|
9031
|
+
}
|
|
9032
|
+
function placeUpright(pdfium, object, geometry, pageX, pageY) {
|
|
9033
|
+
const [a, b, c, d] = ROTATIONS[geometry.rotation % 4];
|
|
9034
|
+
const origin = pageToUser(geometry, pageX, pageY);
|
|
9035
|
+
pdfium.lib.FPDFPageObj_Transform(object, a, b, c, d, origin.x, origin.y);
|
|
9036
|
+
}
|
|
9037
|
+
var ROTATIONS = [
|
|
9038
|
+
[1, 0, 0, 1],
|
|
9039
|
+
[0, 1, -1, 0],
|
|
9040
|
+
[-1, 0, 0, -1],
|
|
9041
|
+
[0, -1, 1, 0]
|
|
9042
|
+
];
|
|
9043
|
+
function setText(pdfium, object, text) {
|
|
9044
|
+
const wide = pdfium.writeWideString(text);
|
|
9045
|
+
try {
|
|
9046
|
+
pdfium.lib.FPDFText_SetText(object, wide);
|
|
9047
|
+
} finally {
|
|
9048
|
+
pdfium.free(wide);
|
|
9049
|
+
}
|
|
9050
|
+
}
|
|
9051
|
+
function parseColor(color) {
|
|
9052
|
+
return [1, 3, 5].map(
|
|
9053
|
+
(offset2) => Number.parseInt(color.slice(offset2, offset2 + 2), 16)
|
|
9054
|
+
);
|
|
9055
|
+
}
|
|
9056
|
+
function resolveStyle(style) {
|
|
9057
|
+
return {
|
|
9058
|
+
fontFamily: style.fontFamily ?? "Helvetica",
|
|
9059
|
+
fontSize: style.fontSize ?? 12,
|
|
9060
|
+
bold: style.bold ?? false,
|
|
9061
|
+
italic: style.italic ?? false,
|
|
9062
|
+
color: style.color ?? "#000000",
|
|
9063
|
+
align: style.align ?? "left",
|
|
9064
|
+
lineHeight: style.lineHeight ?? 1.2
|
|
9065
|
+
};
|
|
9066
|
+
}
|
|
9067
|
+
function definedFields(style) {
|
|
9068
|
+
return Object.fromEntries(
|
|
9069
|
+
Object.entries(style).filter(([, value]) => value !== void 0)
|
|
9070
|
+
);
|
|
9071
|
+
}
|
|
9072
|
+
function validateRect(rect, geometry, issue, path = "/rect") {
|
|
9073
|
+
const size = displayedSize(geometry);
|
|
9074
|
+
const tolerance = 0.01;
|
|
9075
|
+
if (rect.x < -tolerance || rect.y < -tolerance || rect.x + rect.width > size.width + tolerance || rect.y + rect.height > size.height + tolerance)
|
|
9076
|
+
issue(
|
|
9077
|
+
path,
|
|
9078
|
+
"range",
|
|
9079
|
+
`The rectangle must lie within the ${size.width}\xD7${size.height} pt page`
|
|
9080
|
+
);
|
|
9081
|
+
}
|
|
9082
|
+
|
|
9083
|
+
// src/edit/pdf/engine/operations.ts
|
|
9084
|
+
function issueCollector(operationIndex, issues) {
|
|
9085
|
+
return (path, code, message) => issues.push({ operationIndex, path, code, message });
|
|
9086
|
+
}
|
|
9087
|
+
|
|
9088
|
+
// src/edit/pdf/engine/paragraph.ts
|
|
9089
|
+
function paragraphElement(paragraph) {
|
|
9090
|
+
return {
|
|
9091
|
+
id: paragraph.id,
|
|
9092
|
+
kind: "paragraph",
|
|
9093
|
+
pageIndex: paragraph.pageIndex,
|
|
9094
|
+
text: paragraph.text,
|
|
9095
|
+
bounds: paragraph.bounds,
|
|
9096
|
+
textStyle: paragraph.textStyle,
|
|
9097
|
+
operations: [
|
|
9098
|
+
"replaceParagraphText",
|
|
9099
|
+
"replaceText",
|
|
9100
|
+
"setTextStyle",
|
|
9101
|
+
"deleteElement"
|
|
9102
|
+
]
|
|
9103
|
+
};
|
|
9104
|
+
}
|
|
9105
|
+
var MIN_CONTINUATION_FILL = 0.9;
|
|
9106
|
+
var MAX_CONNECTED_EDGE_GAP = 0.65;
|
|
9107
|
+
var MAX_LEFT_ALIGNMENT_DELTA = 1;
|
|
9108
|
+
var ADJACENT_BASELINE_EM = 0.25;
|
|
9109
|
+
var ADJACENT_TEXT_GAP_EM = 3;
|
|
9110
|
+
var LIST_ITEM_START = /^(?:[•◦▪‣·*–—-]|\(?\d{1,3}[.)]|\(?[a-z][.)])\s/iu;
|
|
9111
|
+
var NUMERIC_VALUE = /^[\d\s.,:/%()+−–—-]+$/u;
|
|
9112
|
+
var GLYPH_POSITION_PRECISION = 1e-3;
|
|
9113
|
+
var MAX_PAIR_ADJUSTMENT_EM = 0.1;
|
|
9114
|
+
var MATRIX_RELATIVE_PRECISION = 1e-6;
|
|
9115
|
+
function discoverParagraphs(pdfium, page, pageIndex, geometry, records, elements, textPage, measurer) {
|
|
9116
|
+
const result3 = /* @__PURE__ */ new Map();
|
|
9117
|
+
if (geometry.rotation !== 0) return result3;
|
|
9118
|
+
const indexesById = /* @__PURE__ */ new Map();
|
|
9119
|
+
records.forEach((record, index) => {
|
|
9120
|
+
const indexes = indexesById.get(record.id) ?? [];
|
|
9121
|
+
indexes.push(index);
|
|
9122
|
+
indexesById.set(record.id, indexes);
|
|
9123
|
+
});
|
|
9124
|
+
const elementsById = /* @__PURE__ */ new Map();
|
|
9125
|
+
for (const element of elements)
|
|
9126
|
+
if (!elementsById.has(element.id)) elementsById.set(element.id, element);
|
|
9127
|
+
for (const element of elements) {
|
|
9128
|
+
const indexes = indexesById.get(element.id) ?? [];
|
|
9129
|
+
const spec = paragraphSpecOf(records[indexes[0] ?? -1]?.mark);
|
|
9130
|
+
if (!spec) continue;
|
|
9131
|
+
const paragraph = {
|
|
9132
|
+
id: element.id,
|
|
9133
|
+
pageIndex,
|
|
9134
|
+
text: spec.text,
|
|
9135
|
+
bounds: spec.rect,
|
|
9136
|
+
textStyle: spec.style,
|
|
9137
|
+
memberIds: [element.id],
|
|
9138
|
+
members: [{ elementId: element.id, start: 0, end: spec.text.length }]
|
|
9139
|
+
};
|
|
9140
|
+
result3.set(element.id, { paragraph, spec, indexes });
|
|
9141
|
+
}
|
|
9142
|
+
const rows = [];
|
|
9143
|
+
const uprightTexts = /* @__PURE__ */ new Map();
|
|
9144
|
+
const fontKeys = /* @__PURE__ */ new Map();
|
|
9145
|
+
const programs = [];
|
|
9146
|
+
const fontKey = (font) => {
|
|
9147
|
+
const cached = fontKeys.get(font);
|
|
9148
|
+
if (cached) return cached;
|
|
9149
|
+
let key;
|
|
9150
|
+
if (!pdfium.lib.FPDFFont_GetIsEmbedded(font))
|
|
9151
|
+
key = `standard:${pdfium.readUtf8String((buffer, bytes2) => pdfium.lib.FPDFFont_GetBaseFontName(font, buffer, bytes2))}`;
|
|
9152
|
+
else {
|
|
9153
|
+
const bytes2 = fontBytes(pdfium, font);
|
|
9154
|
+
let at = bytes2 ? programs.findIndex(
|
|
9155
|
+
(program) => program.length === bytes2.length && program.every((byte, index) => byte === bytes2[index])
|
|
9156
|
+
) : -1;
|
|
9157
|
+
if (at < 0 && bytes2) {
|
|
9158
|
+
at = programs.length;
|
|
9159
|
+
programs.push(bytes2);
|
|
9160
|
+
}
|
|
9161
|
+
key = bytes2 ? `embedded:${at}` : `unreadable:${font}`;
|
|
9162
|
+
}
|
|
9163
|
+
fontKeys.set(font, key);
|
|
9164
|
+
return key;
|
|
9165
|
+
};
|
|
9166
|
+
const { lib } = pdfium;
|
|
9167
|
+
const rightEdges = /* @__PURE__ */ new Map();
|
|
9168
|
+
const glyphsByObject = /* @__PURE__ */ new Map();
|
|
9169
|
+
for (let at = 0; at < lib.FPDFText_CountChars(textPage); at += 1) {
|
|
9170
|
+
const unicode = lib.FPDFText_GetUnicode(textPage, at);
|
|
9171
|
+
if (!Number.isInteger(unicode) || unicode < 32 || unicode > 1114111 || unicode >= 55296 && unicode <= 57343)
|
|
9172
|
+
continue;
|
|
9173
|
+
const object = lib.FPDFText_GetTextObject(textPage, at);
|
|
9174
|
+
if (!object) continue;
|
|
9175
|
+
const text = String.fromCodePoint(unicode);
|
|
9176
|
+
const origin = pdfium.readNumbers(
|
|
9177
|
+
2,
|
|
9178
|
+
"double",
|
|
9179
|
+
([x, y]) => lib.FPDFText_GetCharOrigin(textPage, at, x, y)
|
|
9180
|
+
);
|
|
9181
|
+
if (origin) {
|
|
9182
|
+
const point = userToPage(geometry, origin[0], origin[1]);
|
|
9183
|
+
const glyphs = glyphsByObject.get(object) ?? [];
|
|
9184
|
+
glyphs.push({ text, ...point });
|
|
9185
|
+
glyphsByObject.set(object, glyphs);
|
|
9186
|
+
}
|
|
9187
|
+
if (/\s/u.test(text)) continue;
|
|
9188
|
+
const box = pdfium.readNumbers(
|
|
9189
|
+
4,
|
|
9190
|
+
"float",
|
|
9191
|
+
([out]) => lib.FPDFText_GetLooseCharBox(textPage, at, out)
|
|
9192
|
+
);
|
|
9193
|
+
if (box)
|
|
9194
|
+
rightEdges.set(
|
|
9195
|
+
object,
|
|
9196
|
+
Math.max(
|
|
9197
|
+
rightEdges.get(object) ?? -Infinity,
|
|
9198
|
+
userToPage(geometry, box[2], box[1]).x
|
|
9199
|
+
)
|
|
9200
|
+
);
|
|
9201
|
+
}
|
|
9202
|
+
records.forEach((record, index) => {
|
|
9203
|
+
if (record.mark || record.staleMarkId || record.type !== OBJECT_TEXT || record.id.includes("/"))
|
|
9204
|
+
return;
|
|
9205
|
+
const element = elementsById.get(record.id);
|
|
9206
|
+
if (!element?.text?.trim()) return;
|
|
9207
|
+
const object = lib.FPDFPage_GetObject(page, index);
|
|
9208
|
+
const matrix = pdfium.readNumbers(
|
|
9209
|
+
6,
|
|
9210
|
+
"float",
|
|
9211
|
+
([out]) => lib.FPDFPageObj_GetMatrix(object, out)
|
|
9212
|
+
);
|
|
9213
|
+
if (!matrix || matrix[0] <= 0 || matrix[3] <= 0 || Math.abs(matrix[1]) > 1e-3 || Math.abs(matrix[2]) > 1e-3)
|
|
9214
|
+
return;
|
|
9215
|
+
const origin = userToPage(geometry, matrix[4], matrix[5]);
|
|
9216
|
+
uprightTexts.set(element.id, { element, baseline: origin.y });
|
|
9217
|
+
if (!element.textStyle || element.text !== element.text.trimStart() || element.rotation || element.text.includes("") || /[\r\n\t]/u.test(element.text) || LIST_ITEM_START.test(element.text) || NUMERIC_VALUE.test(element.text) || Math.abs(matrix[0] - matrix[3]) > Math.max(matrix[0], matrix[3]) * MATRIX_RELATIVE_PRECISION)
|
|
9218
|
+
return;
|
|
9219
|
+
const rgba = pdfium.readNumbers(
|
|
9220
|
+
4,
|
|
9221
|
+
"i32",
|
|
9222
|
+
([r, g, b, a]) => lib.FPDFPageObj_GetFillColor(object, r, g, b, a)
|
|
9223
|
+
);
|
|
9224
|
+
if (rgba?.[3] !== 255 || lib.FPDFTextObj_GetTextRenderMode(object) !== 0)
|
|
9225
|
+
return;
|
|
9226
|
+
const font = lib.FPDFTextObj_GetFont(object);
|
|
9227
|
+
const rawSize = pdfium.readNumbers(
|
|
9228
|
+
1,
|
|
9229
|
+
"float",
|
|
9230
|
+
([out]) => lib.FPDFTextObj_GetFontSize(object, out)
|
|
9231
|
+
)?.[0];
|
|
9232
|
+
if (!rawSize) return;
|
|
9233
|
+
const effective = {
|
|
9234
|
+
...element,
|
|
9235
|
+
textStyle: {
|
|
9236
|
+
...element.textStyle,
|
|
9237
|
+
fontSize: round(rawSize * matrix[0])
|
|
9238
|
+
}
|
|
9239
|
+
};
|
|
9240
|
+
if (effective.textStyle.fontSize < 1 || effective.textStyle.fontSize > 500)
|
|
9241
|
+
return;
|
|
9242
|
+
if (fontCanDraw(pdfium, font, element.text) && !hasSupportedAdvances(
|
|
9243
|
+
glyphsByObject.get(object) ?? [],
|
|
9244
|
+
element.text,
|
|
9245
|
+
font,
|
|
9246
|
+
rawSize * matrix[0],
|
|
9247
|
+
measurer
|
|
9248
|
+
))
|
|
9249
|
+
return;
|
|
9250
|
+
const width = (rightEdges.get(object) ?? element.bounds.x + element.bounds.width) - origin.x;
|
|
9251
|
+
if (!(width > 0) || element.bounds.width > width + 2) return;
|
|
9252
|
+
rows.push({
|
|
9253
|
+
element: effective,
|
|
9254
|
+
index,
|
|
9255
|
+
font: fontKey(font),
|
|
9256
|
+
fontHandle: font,
|
|
9257
|
+
x: origin.x,
|
|
9258
|
+
baseline: origin.y,
|
|
9259
|
+
width,
|
|
9260
|
+
firstWordAdvance: observedFirstWordAdvance(
|
|
9261
|
+
glyphsByObject.get(object) ?? [],
|
|
9262
|
+
element.text
|
|
9263
|
+
)
|
|
9264
|
+
});
|
|
9265
|
+
});
|
|
9266
|
+
rows.sort((a, b) => a.baseline - b.baseline || a.x - b.x);
|
|
9267
|
+
const blockedRows = rowsWithAdjacentText(rows, [...uprightTexts.values()]);
|
|
9268
|
+
const used = /* @__PURE__ */ new Set();
|
|
9269
|
+
for (const first of rows) {
|
|
9270
|
+
if (used.has(first.element.id) || blockedRows.has(first.element.id))
|
|
9271
|
+
continue;
|
|
9272
|
+
const aligned = rows.filter(
|
|
9273
|
+
(row) => !used.has(row.element.id) && row.baseline >= first.baseline && compatible(first, row)
|
|
9274
|
+
);
|
|
9275
|
+
const gaps = aligned.slice(1).map((row, index) => row.baseline - aligned[index].baseline).filter(
|
|
9276
|
+
(gap) => gap >= first.element.textStyle.fontSize * 0.8 && gap <= first.element.textStyle.fontSize * 2.1
|
|
9277
|
+
);
|
|
9278
|
+
if (gaps.length === 0) continue;
|
|
9279
|
+
const leading = Math.min(...gaps);
|
|
9280
|
+
const group = [];
|
|
9281
|
+
for (const row of aligned) {
|
|
9282
|
+
const previous = group.at(-1);
|
|
9283
|
+
if (previous && (Math.abs(row.baseline - previous.baseline - leading) > Math.max(1, leading * 0.15) || /[-\u00ad\u0002]$/u.test(previous.element.text.trim())))
|
|
9284
|
+
break;
|
|
9285
|
+
group.push(row);
|
|
9286
|
+
}
|
|
9287
|
+
if (group.length < 2 || group.some((row) => blockedRows.has(row.element.id)))
|
|
9288
|
+
continue;
|
|
9289
|
+
const bounds = unionRects(group.map((row) => row.element.bounds));
|
|
9290
|
+
const rect = roundRect({
|
|
9291
|
+
x: first.x,
|
|
9292
|
+
y: bounds.y,
|
|
9293
|
+
width: Math.max(...group.map((row) => row.width)),
|
|
9294
|
+
height: bounds.height
|
|
9295
|
+
});
|
|
9296
|
+
const ids = new Set(group.map((row) => row.element.id));
|
|
9297
|
+
const firstIndex = Math.min(...group.map((row) => row.index));
|
|
9298
|
+
if (group.slice(0, -1).some(
|
|
9299
|
+
(row, index) => !continuesAtWrap(
|
|
9300
|
+
row,
|
|
9301
|
+
group[index + 1],
|
|
9302
|
+
rect.width,
|
|
9303
|
+
pdfium,
|
|
9304
|
+
measurer
|
|
9305
|
+
)
|
|
9306
|
+
) || elements.some((element) => {
|
|
9307
|
+
if (ids.has(element.id) || !element.text?.trim()) return false;
|
|
9308
|
+
const b = element.bounds;
|
|
9309
|
+
const upright = uprightTexts.get(element.id);
|
|
9310
|
+
const sharesRow = upright && group.some((row) => isAdjacentText(row, upright));
|
|
9311
|
+
if (sharesRow) return true;
|
|
9312
|
+
const sharesColumn = b.x < rect.x + rect.width && b.x + b.width > rect.x;
|
|
9313
|
+
const edgeGap = Math.max(
|
|
9314
|
+
b.y - (rect.y + rect.height),
|
|
9315
|
+
rect.y - (b.y + b.height)
|
|
9316
|
+
);
|
|
9317
|
+
return sharesColumn && edgeGap <= leading * MAX_CONNECTED_EDGE_GAP;
|
|
9318
|
+
}))
|
|
9319
|
+
continue;
|
|
9320
|
+
if (elements.some(
|
|
9321
|
+
(element) => !ids.has(element.id) && intersects(rect, element.bounds) && !backgroundBehind(element, rect, records, firstIndex)
|
|
9322
|
+
))
|
|
9323
|
+
continue;
|
|
9324
|
+
const id = `${first.element.id}:paragraph`;
|
|
9325
|
+
if (elementsById.has(id)) continue;
|
|
9326
|
+
let text = "";
|
|
9327
|
+
const members = group.map((row) => {
|
|
9328
|
+
if (text) text += " ";
|
|
9329
|
+
const start = text.length;
|
|
9330
|
+
text += row.element.text.trim();
|
|
9331
|
+
return { elementId: row.element.id, start, end: text.length };
|
|
9332
|
+
});
|
|
9333
|
+
if (text.length > 2e4) continue;
|
|
9334
|
+
const style = {
|
|
9335
|
+
...first.element.textStyle,
|
|
9336
|
+
lineHeight: leading / first.element.textStyle.fontSize
|
|
9337
|
+
};
|
|
9338
|
+
const paragraph = {
|
|
9339
|
+
id,
|
|
9340
|
+
pageIndex,
|
|
9341
|
+
text,
|
|
9342
|
+
bounds: rect,
|
|
9343
|
+
textStyle: style,
|
|
9344
|
+
memberIds: [...ids],
|
|
9345
|
+
members
|
|
9346
|
+
};
|
|
9347
|
+
const target = {
|
|
9348
|
+
paragraph,
|
|
9349
|
+
spec: {
|
|
9350
|
+
kind: "paragraph",
|
|
9351
|
+
id,
|
|
9352
|
+
text,
|
|
9353
|
+
lines: group.map((row) => row.element.text.trim()),
|
|
9354
|
+
rect,
|
|
9355
|
+
style,
|
|
9356
|
+
baselineOffset: (first.baseline - rect.y) / style.fontSize
|
|
9357
|
+
},
|
|
9358
|
+
indexes: group.map((row) => row.index).sort((a, b) => a - b)
|
|
9359
|
+
};
|
|
9360
|
+
result3.set(id, target);
|
|
9361
|
+
for (const member of members) {
|
|
9362
|
+
result3.set(member.elementId, target);
|
|
9363
|
+
used.add(member.elementId);
|
|
9364
|
+
}
|
|
9365
|
+
}
|
|
9366
|
+
return result3;
|
|
9367
|
+
}
|
|
9368
|
+
function compatible(a, b) {
|
|
9369
|
+
return Math.abs(a.x - b.x) <= MAX_LEFT_ALIGNMENT_DELTA && sameTypography(a, b);
|
|
9370
|
+
}
|
|
9371
|
+
function sameTypography(a, b) {
|
|
9372
|
+
const x = a.element.textStyle;
|
|
9373
|
+
const y = b.element.textStyle;
|
|
9374
|
+
return a.font === b.font && x.fontSize === y.fontSize && x.color === y.color && x.bold === y.bold && x.italic === y.italic;
|
|
9375
|
+
}
|
|
9376
|
+
function rowsWithAdjacentText(rows, texts) {
|
|
9377
|
+
texts.sort((a, b) => a.baseline - b.baseline);
|
|
9378
|
+
const blocked = /* @__PURE__ */ new Set();
|
|
9379
|
+
for (const row of rows) {
|
|
9380
|
+
const tolerance = row.element.textStyle.fontSize * ADJACENT_BASELINE_EM;
|
|
9381
|
+
let low = 0;
|
|
9382
|
+
let high = texts.length;
|
|
9383
|
+
while (low < high) {
|
|
9384
|
+
const mid = low + high >>> 1;
|
|
9385
|
+
if (texts[mid].baseline < row.baseline - tolerance) low = mid + 1;
|
|
9386
|
+
else high = mid;
|
|
9387
|
+
}
|
|
9388
|
+
for (let at = low; at < texts.length; at += 1) {
|
|
9389
|
+
const other = texts[at];
|
|
9390
|
+
if (other.baseline > row.baseline + tolerance) break;
|
|
9391
|
+
if (isAdjacentText(row, other)) {
|
|
9392
|
+
blocked.add(row.element.id);
|
|
9393
|
+
break;
|
|
9394
|
+
}
|
|
9395
|
+
}
|
|
9396
|
+
}
|
|
9397
|
+
return blocked;
|
|
9398
|
+
}
|
|
9399
|
+
function isAdjacentText(row, other) {
|
|
9400
|
+
if (row.element.id === other.element.id) return false;
|
|
9401
|
+
const size = row.element.textStyle.fontSize;
|
|
9402
|
+
if (Math.abs(row.baseline - other.baseline) > size * ADJACENT_BASELINE_EM)
|
|
9403
|
+
return false;
|
|
9404
|
+
const a = row.element.bounds;
|
|
9405
|
+
const b = other.element.bounds;
|
|
9406
|
+
const gap = Math.max(b.x - (a.x + a.width), a.x - (b.x + b.width));
|
|
9407
|
+
return gap <= size * ADJACENT_TEXT_GAP_EM;
|
|
9408
|
+
}
|
|
9409
|
+
function continuesAtWrap(row, next, width, pdfium, measurer) {
|
|
9410
|
+
if (row.width >= width * MIN_CONTINUATION_FILL) return true;
|
|
9411
|
+
if (next.firstWordAdvance !== void 0)
|
|
9412
|
+
return row.width + next.firstWordAdvance > width + GLYPH_POSITION_PRECISION;
|
|
9413
|
+
const nextWord = next.element.text.trim().split(/\s/u)[0];
|
|
9414
|
+
if (!nextWord || !fontCanDraw(pdfium, row.fontHandle, ` ${nextWord}`))
|
|
9415
|
+
return false;
|
|
9416
|
+
const needed = measurer.advance(
|
|
9417
|
+
row.fontHandle,
|
|
9418
|
+
row.element.textStyle.fontSize,
|
|
9419
|
+
` ${nextWord}`
|
|
9420
|
+
);
|
|
9421
|
+
return Number.isFinite(needed) && row.width + needed > width + GLYPH_POSITION_PRECISION;
|
|
9422
|
+
}
|
|
9423
|
+
function observedFirstWordAdvance(glyphs, text) {
|
|
9424
|
+
const prefix = /^\S+\s+/u.exec(text)?.[0];
|
|
9425
|
+
if (!prefix) return void 0;
|
|
9426
|
+
const count = [...prefix].length;
|
|
9427
|
+
const first = glyphs[0];
|
|
9428
|
+
const nextWord = glyphs[count];
|
|
9429
|
+
if (!first || !nextWord || glyphs.slice(0, count).map((glyph) => glyph.text).join("") !== prefix)
|
|
9430
|
+
return void 0;
|
|
9431
|
+
const advance2 = nextWord.x - first.x;
|
|
9432
|
+
return Number.isFinite(advance2) && advance2 > 0 ? advance2 : void 0;
|
|
9433
|
+
}
|
|
9434
|
+
function hasSupportedAdvances(glyphs, text, font, fontSize, measurer) {
|
|
9435
|
+
const characters = [...text.trimEnd()];
|
|
9436
|
+
const first = glyphs[0];
|
|
9437
|
+
if (!first || glyphs.length < characters.length) return false;
|
|
9438
|
+
const pairLimit = fontSize * MAX_PAIR_ADJUSTMENT_EM;
|
|
9439
|
+
let previousAdvance = 0;
|
|
9440
|
+
let cumulativeAdjustment = 0;
|
|
9441
|
+
let adjustedPairs = 0;
|
|
9442
|
+
let defaultPairs = 0;
|
|
9443
|
+
for (const [index, character] of characters.entries()) {
|
|
9444
|
+
const glyph = glyphs[index];
|
|
9445
|
+
if (!glyph || glyph.text !== character || !Number.isFinite(glyph.x) || !Number.isFinite(glyph.y) || Math.abs(glyph.y - first.y) > GLYPH_POSITION_PRECISION)
|
|
9446
|
+
return false;
|
|
9447
|
+
const previous = glyphs[index - 1];
|
|
9448
|
+
if (previous) {
|
|
9449
|
+
const adjustment = glyph.x - previous.x - previousAdvance;
|
|
9450
|
+
const changed2 = Math.abs(adjustment) > GLYPH_POSITION_PRECISION;
|
|
9451
|
+
if (/\s/u.test(previous.text + character)) {
|
|
9452
|
+
if (changed2) return false;
|
|
9453
|
+
} else if (changed2) {
|
|
9454
|
+
if (Math.abs(adjustment) > pairLimit) return false;
|
|
9455
|
+
adjustedPairs += 1;
|
|
9456
|
+
} else {
|
|
9457
|
+
defaultPairs += 1;
|
|
9458
|
+
}
|
|
9459
|
+
cumulativeAdjustment += adjustment;
|
|
9460
|
+
if (Math.abs(cumulativeAdjustment) > pairLimit) return false;
|
|
9461
|
+
}
|
|
9462
|
+
previousAdvance = measurer.advance(font, fontSize, character);
|
|
9463
|
+
if (!Number.isFinite(previousAdvance) || previousAdvance <= 0) return false;
|
|
9464
|
+
}
|
|
9465
|
+
return adjustedPairs === 0 || defaultPairs > adjustedPairs;
|
|
9466
|
+
}
|
|
9467
|
+
function intersects(a, b) {
|
|
9468
|
+
return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
|
|
9469
|
+
}
|
|
9470
|
+
function backgroundBehind(element, rect, records, first) {
|
|
9471
|
+
const b = element.bounds;
|
|
9472
|
+
return element.kind !== "text" && element.text === void 0 && records.findIndex((record) => record.id === element.id) < first && b.x <= rect.x && b.y <= rect.y && b.x + b.width >= rect.x + rect.width && b.y + b.height >= rect.y + rect.height;
|
|
9473
|
+
}
|
|
9474
|
+
|
|
9475
|
+
// src/edit/pdf/engine/paragraph-edit.ts
|
|
9476
|
+
var replaceParagraphText = {
|
|
9477
|
+
validate(operation2, context, issue) {
|
|
9478
|
+
const target = targetOf(operation2.target, context, issue);
|
|
9479
|
+
if (!target) return;
|
|
9480
|
+
const text = replacement(operation2, target.spec.text, issue);
|
|
9481
|
+
if (text === void 0 || !validateScript(text, issue)) return;
|
|
9482
|
+
if (text.length > 2e4) {
|
|
9483
|
+
issue(
|
|
9484
|
+
"/text",
|
|
9485
|
+
"max-length",
|
|
9486
|
+
"The complete paragraph cannot exceed 20000 characters"
|
|
9487
|
+
);
|
|
9488
|
+
return;
|
|
9489
|
+
}
|
|
9490
|
+
prepare(context, target, { ...target.spec, text }, issue);
|
|
9491
|
+
},
|
|
9492
|
+
apply(operation2, context) {
|
|
9493
|
+
const target = requireTarget(operation2.target, context);
|
|
9494
|
+
const text = replacement(operation2, target.spec.text);
|
|
9495
|
+
if (text === void 0)
|
|
9496
|
+
throw new ViewerError("invalid-operation", "Invalid paragraph range");
|
|
9497
|
+
return rebuild(context, target, { ...target.spec, text });
|
|
9498
|
+
}
|
|
9499
|
+
};
|
|
9500
|
+
var paragraphSetTextStyle = {
|
|
9501
|
+
validate(operation2, context, issue) {
|
|
9502
|
+
const target = targetOf(operation2.target, context, issue);
|
|
9503
|
+
if (!target) return;
|
|
9504
|
+
for (const field of [
|
|
9505
|
+
"fontFamily",
|
|
9506
|
+
"bold",
|
|
9507
|
+
"italic",
|
|
9508
|
+
"align",
|
|
9509
|
+
"lineHeight"
|
|
9510
|
+
])
|
|
9511
|
+
if (operation2.style[field] !== void 0)
|
|
9512
|
+
issue(
|
|
9513
|
+
`/style/${field}`,
|
|
9514
|
+
"unsupported-style",
|
|
9515
|
+
`Only color and fontSize can change on imported paragraphs; ${field} cannot`
|
|
9516
|
+
);
|
|
9517
|
+
const spec = styled(target.spec, operation2);
|
|
9518
|
+
if (spec.style.fontSize !== target.spec.style.fontSize)
|
|
9519
|
+
prepare(context, target, spec, issue);
|
|
9520
|
+
},
|
|
9521
|
+
apply(operation2, context) {
|
|
9522
|
+
const target = requireTarget(operation2.target, context);
|
|
9523
|
+
const spec = styled(target.spec, operation2);
|
|
9524
|
+
if (spec.style.fontSize === target.spec.style.fontSize)
|
|
9525
|
+
return colorInPlace(context, target, spec);
|
|
9526
|
+
return rebuild(context, target, spec);
|
|
9527
|
+
}
|
|
9528
|
+
};
|
|
9529
|
+
function colorInPlace(context, target, spec) {
|
|
9530
|
+
const { pdfium } = context;
|
|
9531
|
+
const { lib } = pdfium;
|
|
9532
|
+
const color = parseColor(spec.style.color);
|
|
9533
|
+
const persisted = target.paragraph.memberIds.includes(spec.id);
|
|
9534
|
+
context.withPage(target.paragraph.pageIndex, (page) => {
|
|
9535
|
+
for (const index of target.indexes) {
|
|
9536
|
+
const object = lib.FPDFPage_GetObject(page, index);
|
|
9537
|
+
if (lib.FPDFPageObj_GetType(object) === OBJECT_TEXT)
|
|
9538
|
+
lib.FPDFPageObj_SetFillColor(object, ...color, 255);
|
|
9539
|
+
if (!persisted) continue;
|
|
9540
|
+
for (let at = 0; at < lib.FPDFPageObj_CountMarks(object); at += 1) {
|
|
9541
|
+
const mark = lib.FPDFPageObj_GetMark(object, at);
|
|
9542
|
+
const name = pdfium.readWideStringOut(
|
|
9543
|
+
(buffer, bytes2, out) => lib.FPDFPageObjMark_GetName(mark, buffer, bytes2, out)
|
|
9544
|
+
);
|
|
9545
|
+
if (name === MARK_NAME)
|
|
9546
|
+
lib.FPDFPageObjMark_SetStringParam(
|
|
9547
|
+
context.document,
|
|
9548
|
+
object,
|
|
9549
|
+
mark,
|
|
9550
|
+
MARK_PARAM,
|
|
9551
|
+
JSON.stringify(spec)
|
|
9552
|
+
);
|
|
9553
|
+
}
|
|
9554
|
+
context.spliceObjects(target.paragraph.pageIndex, index, 1, [
|
|
9555
|
+
{ id: spec.id, type: lib.FPDFPageObj_GetType(object), mark: spec }
|
|
9556
|
+
]);
|
|
8818
9557
|
}
|
|
8819
|
-
}
|
|
8820
|
-
return requests;
|
|
8821
|
-
}
|
|
8822
|
-
function fontRequest(style, text) {
|
|
9558
|
+
});
|
|
8823
9559
|
return {
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
text
|
|
9560
|
+
createdIds: [],
|
|
9561
|
+
changedPages: [target.paragraph.pageIndex],
|
|
9562
|
+
warnings: []
|
|
8828
9563
|
};
|
|
8829
9564
|
}
|
|
8830
|
-
function
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
8837
|
-
|
|
9565
|
+
function styled(spec, operation2) {
|
|
9566
|
+
return {
|
|
9567
|
+
...spec,
|
|
9568
|
+
style: {
|
|
9569
|
+
...spec.style,
|
|
9570
|
+
...operation2.style.fontSize === void 0 ? {} : { fontSize: round(operation2.style.fontSize) },
|
|
9571
|
+
...operation2.style.color === void 0 ? {} : { color: operation2.style.color }
|
|
9572
|
+
}
|
|
9573
|
+
};
|
|
8838
9574
|
}
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
pdfium.lib.FPDFText_SetText(object, wide);
|
|
8849
|
-
} finally {
|
|
8850
|
-
pdfium.free(wide);
|
|
9575
|
+
function targetOf(id, context, issue) {
|
|
9576
|
+
const target = context.paragraph(id);
|
|
9577
|
+
if (!target || target.paragraph.id !== id) {
|
|
9578
|
+
issue(
|
|
9579
|
+
"/target",
|
|
9580
|
+
"unsupported-target",
|
|
9581
|
+
"The target must be a resolved native paragraph id"
|
|
9582
|
+
);
|
|
9583
|
+
return void 0;
|
|
8851
9584
|
}
|
|
9585
|
+
return target;
|
|
8852
9586
|
}
|
|
8853
|
-
function
|
|
8854
|
-
|
|
8855
|
-
|
|
9587
|
+
function requireTarget(id, context) {
|
|
9588
|
+
const target = targetOf(id, context, () => {
|
|
9589
|
+
});
|
|
9590
|
+
if (!target)
|
|
9591
|
+
throw new ViewerError(
|
|
9592
|
+
"invalid-operation",
|
|
9593
|
+
"The paragraph no longer exists"
|
|
9594
|
+
);
|
|
9595
|
+
return target;
|
|
9596
|
+
}
|
|
9597
|
+
function replacement(operation2, previous, issue = () => {
|
|
9598
|
+
}) {
|
|
9599
|
+
const range = operation2.range;
|
|
9600
|
+
if (!range) return operation2.text;
|
|
9601
|
+
const valid = [range.start, range.end].every(
|
|
9602
|
+
(position) => position.elementId === operation2.target && Number.isInteger(position.offset) && position.offset >= 0 && position.offset <= previous.length
|
|
8856
9603
|
);
|
|
9604
|
+
if (!valid || range.start.offset > range.end.offset) {
|
|
9605
|
+
issue(
|
|
9606
|
+
"/range",
|
|
9607
|
+
"invalid-range",
|
|
9608
|
+
"The range must lie inside the paragraph's logical text"
|
|
9609
|
+
);
|
|
9610
|
+
return void 0;
|
|
9611
|
+
}
|
|
9612
|
+
return previous.slice(0, range.start.offset) + operation2.text + previous.slice(range.end.offset);
|
|
8857
9613
|
}
|
|
8858
|
-
function
|
|
9614
|
+
function fontFor(context, target, spec, page) {
|
|
9615
|
+
const { lib } = context.pdfium;
|
|
9616
|
+
const original = target.indexes.map((index) => lib.FPDFPage_GetObject(page, index)).find((object) => lib.FPDFPageObj_GetType(object) === OBJECT_TEXT);
|
|
9617
|
+
const native = original === void 0 ? void 0 : lib.FPDFTextObj_GetFont(original);
|
|
9618
|
+
if (native !== void 0 && fontCanDraw(context.pdfium, native, spec.text))
|
|
9619
|
+
return {
|
|
9620
|
+
handle: native,
|
|
9621
|
+
family: spec.style.fontFamily,
|
|
9622
|
+
substituted: false
|
|
9623
|
+
};
|
|
9624
|
+
const family = isStandardFamily(spec.style.fontFamily) || context.fonts.hasFamily(spec.style.fontFamily) ? spec.style.fontFamily : "Helvetica";
|
|
9625
|
+
const request = {
|
|
9626
|
+
family,
|
|
9627
|
+
bold: spec.style.bold,
|
|
9628
|
+
italic: spec.style.italic,
|
|
9629
|
+
text: spec.text
|
|
9630
|
+
};
|
|
9631
|
+
const problem = context.fonts.problem(request);
|
|
9632
|
+
if (problem) return { problem };
|
|
9633
|
+
const font = context.fonts.resolve(context.pdfium, context.document, request);
|
|
8859
9634
|
return {
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
color: style.color ?? "#000000",
|
|
8865
|
-
align: style.align ?? "left",
|
|
8866
|
-
lineHeight: style.lineHeight ?? 1.2
|
|
9635
|
+
handle: font.handle,
|
|
9636
|
+
family: font.family,
|
|
9637
|
+
substituted: original !== void 0 || !isStandardFamily(spec.style.fontFamily),
|
|
9638
|
+
...font.substitution ? { substitution: font.substitution } : {}
|
|
8867
9639
|
};
|
|
8868
9640
|
}
|
|
8869
|
-
function
|
|
8870
|
-
return
|
|
8871
|
-
|
|
8872
|
-
|
|
9641
|
+
function prepare(context, target, spec, issue) {
|
|
9642
|
+
return context.readPage(target.paragraph.pageIndex, (page) => {
|
|
9643
|
+
const font = fontFor(context, target, spec, page);
|
|
9644
|
+
if ("problem" in font) {
|
|
9645
|
+
issue(font.problem.path, font.problem.code, font.problem.message);
|
|
9646
|
+
return void 0;
|
|
9647
|
+
}
|
|
9648
|
+
const metrics = context.measurer.metrics(font.handle, spec.style.fontSize);
|
|
9649
|
+
const layout = layoutText({
|
|
9650
|
+
text: spec.text,
|
|
9651
|
+
width: spec.rect.width,
|
|
9652
|
+
height: Number.POSITIVE_INFINITY,
|
|
9653
|
+
fontSize: spec.style.fontSize,
|
|
9654
|
+
lineHeight: spec.style.lineHeight,
|
|
9655
|
+
align: "left",
|
|
9656
|
+
ascent: spec.baselineOffset * spec.style.fontSize,
|
|
9657
|
+
advance: (text) => context.measurer.advance(font.handle, spec.style.fontSize, text)
|
|
9658
|
+
});
|
|
9659
|
+
const last = layout.lines.at(-1);
|
|
9660
|
+
const height = spec.text.trim() && last ? last.baseline + metrics.descent : spec.rect.height;
|
|
9661
|
+
const rect = { ...spec.rect, height: Math.max(height, 1e-3) };
|
|
9662
|
+
const size = context.pageSize(target.paragraph.pageIndex);
|
|
9663
|
+
const members = new Set(target.paragraph.memberIds);
|
|
9664
|
+
const collision = context.pageElements(target.paragraph.pageIndex).some((element) => {
|
|
9665
|
+
if (members.has(element.id) || !intersects(rect, element.bounds))
|
|
9666
|
+
return false;
|
|
9667
|
+
const old = target.spec.rect;
|
|
9668
|
+
const b = element.bounds;
|
|
9669
|
+
const location = context.locate(element.id);
|
|
9670
|
+
const behind = location && location.indexes.every((index) => index < target.indexes[0]);
|
|
9671
|
+
return !(element.text === void 0 && behind && b.x <= old.x && b.y <= old.y && b.x + b.width >= rect.x + rect.width && b.y + b.height >= rect.y + rect.height);
|
|
9672
|
+
});
|
|
9673
|
+
if (collision || rect.x < 0 || rect.y < 0 || rect.x + rect.width > size.width + 0.01 || rect.y + rect.height > size.height + 0.01) {
|
|
9674
|
+
issue(
|
|
9675
|
+
"/text",
|
|
9676
|
+
"paragraph-overflow",
|
|
9677
|
+
"The paragraph would overlap neighboring content or leave the page"
|
|
9678
|
+
);
|
|
9679
|
+
return void 0;
|
|
9680
|
+
}
|
|
9681
|
+
const warnings = font.substituted ? [
|
|
9682
|
+
{
|
|
9683
|
+
code: "font-substitution",
|
|
9684
|
+
message: "substitution" in font && font.substitution ? font.substitution : `${spec.style.fontFamily} cannot draw the new paragraph; ${font.family} is used`,
|
|
9685
|
+
details: { elementId: spec.id }
|
|
9686
|
+
}
|
|
9687
|
+
] : [];
|
|
9688
|
+
return {
|
|
9689
|
+
spec: {
|
|
9690
|
+
...spec,
|
|
9691
|
+
rect,
|
|
9692
|
+
lines: layout.lines.map((line) => line.text).filter(Boolean),
|
|
9693
|
+
style: {
|
|
9694
|
+
...spec.style,
|
|
9695
|
+
fontFamily: font.substituted ? font.family : spec.style.fontFamily
|
|
9696
|
+
}
|
|
9697
|
+
},
|
|
9698
|
+
layout,
|
|
9699
|
+
warnings
|
|
9700
|
+
};
|
|
9701
|
+
});
|
|
8873
9702
|
}
|
|
8874
|
-
function
|
|
8875
|
-
const
|
|
8876
|
-
const
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
9703
|
+
function rebuild(context, target, spec) {
|
|
9704
|
+
const issues = [];
|
|
9705
|
+
const prepared = prepare(
|
|
9706
|
+
context,
|
|
9707
|
+
target,
|
|
9708
|
+
spec,
|
|
9709
|
+
(path, code, message) => issues.push({ path, code, message })
|
|
9710
|
+
);
|
|
9711
|
+
if (!prepared)
|
|
9712
|
+
throw new ViewerError(
|
|
9713
|
+
"invalid-operation",
|
|
9714
|
+
"The paragraph cannot be changed",
|
|
9715
|
+
{ details: { issues } }
|
|
8882
9716
|
);
|
|
8883
|
-
}
|
|
8884
|
-
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
|
|
9717
|
+
const { pdfium } = context;
|
|
9718
|
+
const { lib } = pdfium;
|
|
9719
|
+
const pageIndex = target.paragraph.pageIndex;
|
|
9720
|
+
const geometry = context.geometry(pageIndex);
|
|
9721
|
+
const first = target.indexes[0];
|
|
9722
|
+
context.withPage(pageIndex, (page) => {
|
|
9723
|
+
const font = fontFor(context, target, spec, page);
|
|
9724
|
+
if ("problem" in font)
|
|
9725
|
+
throw new ViewerError("invalid-operation", font.problem.message);
|
|
9726
|
+
const objects = [];
|
|
9727
|
+
const [r, g, b] = parseColor(spec.style.color);
|
|
9728
|
+
if (!spec.text.trim()) {
|
|
9729
|
+
const rect = prepared.spec.rect;
|
|
9730
|
+
const origin = pageToUser(geometry, rect.x, rect.y + rect.height);
|
|
9731
|
+
const object = lib.FPDFPageObj_CreateNewRect(
|
|
9732
|
+
origin.x,
|
|
9733
|
+
origin.y,
|
|
9734
|
+
rect.width,
|
|
9735
|
+
rect.height
|
|
9736
|
+
);
|
|
9737
|
+
lib.FPDFPageObj_SetFillColor(object, 0, 0, 0, 0);
|
|
9738
|
+
lib.FPDFPath_SetDrawMode(object, 1, false);
|
|
9739
|
+
objects.push({ object, type: OBJECT_PATH });
|
|
9740
|
+
} else
|
|
9741
|
+
for (const line of prepared.layout.lines) {
|
|
9742
|
+
if (!line.text) continue;
|
|
9743
|
+
const object = lib.FPDFPageObj_CreateTextObj(
|
|
9744
|
+
context.document,
|
|
9745
|
+
font.handle,
|
|
9746
|
+
spec.style.fontSize
|
|
9747
|
+
);
|
|
9748
|
+
if (!object) {
|
|
9749
|
+
for (const made of objects) lib.FPDFPageObj_Destroy(made.object);
|
|
9750
|
+
throw new ViewerError(
|
|
9751
|
+
"edit-failed",
|
|
9752
|
+
"PDFium could not create paragraph text"
|
|
9753
|
+
);
|
|
9754
|
+
}
|
|
9755
|
+
setText(pdfium, object, line.text);
|
|
9756
|
+
lib.FPDFPageObj_SetFillColor(object, r, g, b, 255);
|
|
9757
|
+
placeUpright(
|
|
9758
|
+
pdfium,
|
|
9759
|
+
object,
|
|
9760
|
+
geometry,
|
|
9761
|
+
spec.rect.x + line.x,
|
|
9762
|
+
spec.rect.y + line.baseline
|
|
9763
|
+
);
|
|
9764
|
+
objects.push({ object, type: OBJECT_TEXT });
|
|
9765
|
+
}
|
|
9766
|
+
const params = JSON.stringify(prepared.spec);
|
|
9767
|
+
for (const { object } of objects) {
|
|
9768
|
+
const mark = lib.FPDFPageObj_AddMark(object, MARK_NAME);
|
|
9769
|
+
lib.FPDFPageObjMark_SetStringParam(
|
|
9770
|
+
context.document,
|
|
9771
|
+
object,
|
|
9772
|
+
mark,
|
|
9773
|
+
MARK_PARAM,
|
|
9774
|
+
params
|
|
9775
|
+
);
|
|
9776
|
+
}
|
|
9777
|
+
for (const index of [...target.indexes].reverse()) {
|
|
9778
|
+
const object = lib.FPDFPage_GetObject(page, index);
|
|
9779
|
+
lib.FPDFPage_RemoveObject(page, object);
|
|
9780
|
+
lib.FPDFPageObj_Destroy(object);
|
|
9781
|
+
context.spliceObjects(pageIndex, index, 1, []);
|
|
9782
|
+
}
|
|
9783
|
+
objects.forEach(
|
|
9784
|
+
({ object }, at) => lib.FPDFPage_InsertObjectAtIndex(page, object, first + at)
|
|
9785
|
+
);
|
|
9786
|
+
const textPage = lib.FPDFText_LoadPage(page);
|
|
9787
|
+
try {
|
|
9788
|
+
const drawn = objects.filter(({ type }) => type === OBJECT_TEXT).map(
|
|
9789
|
+
({ object }) => pdfium.readWideString(
|
|
9790
|
+
(buffer, bytes2) => lib.FPDFTextObj_GetText(object, textPage, buffer, bytes2)
|
|
9791
|
+
).trimEnd()
|
|
9792
|
+
);
|
|
9793
|
+
if (drawn.length !== prepared.spec.lines.length || drawn.some((line, index) => line !== prepared.spec.lines[index]))
|
|
9794
|
+
throw new ViewerError(
|
|
9795
|
+
"edit-failed",
|
|
9796
|
+
"The native font could not encode the paragraph faithfully"
|
|
9797
|
+
);
|
|
9798
|
+
} finally {
|
|
9799
|
+
lib.FPDFText_ClosePage(textPage);
|
|
9800
|
+
}
|
|
9801
|
+
context.spliceObjects(
|
|
9802
|
+
pageIndex,
|
|
9803
|
+
first,
|
|
9804
|
+
0,
|
|
9805
|
+
objects.map(({ type }) => ({ id: spec.id, type, mark: prepared.spec }))
|
|
9806
|
+
);
|
|
9807
|
+
});
|
|
9808
|
+
const promoted = !target.paragraph.memberIds.includes(spec.id);
|
|
9809
|
+
return {
|
|
9810
|
+
createdIds: [],
|
|
9811
|
+
removedIds: promoted ? target.paragraph.memberIds : [],
|
|
9812
|
+
...promoted ? {
|
|
9813
|
+
textAnchorMigrations: target.paragraph.members.map((member) => ({
|
|
9814
|
+
sourceElementId: member.elementId,
|
|
9815
|
+
targetElementId: spec.id,
|
|
9816
|
+
sourceLength: member.end - member.start,
|
|
9817
|
+
targetOffset: member.start
|
|
9818
|
+
}))
|
|
9819
|
+
} : {},
|
|
9820
|
+
changedPages: [pageIndex],
|
|
9821
|
+
warnings: prepared.warnings
|
|
9822
|
+
};
|
|
8888
9823
|
}
|
|
8889
9824
|
|
|
8890
9825
|
// src/edit/pdf/engine/existing-text.ts
|
|
8891
9826
|
var replaceText = {
|
|
8892
9827
|
validate(operation2, context, issue) {
|
|
9828
|
+
if (context.paragraph(operation2.target)?.paragraph.id === operation2.target)
|
|
9829
|
+
return replaceParagraphText.validate(
|
|
9830
|
+
{ ...operation2, op: "replaceParagraphText" },
|
|
9831
|
+
context,
|
|
9832
|
+
issue
|
|
9833
|
+
);
|
|
8893
9834
|
const box = textBoxTarget(operation2.target, context);
|
|
8894
9835
|
if (box) {
|
|
8895
9836
|
const spliced = splice(box.spec.text, operation2, issue);
|
|
@@ -8918,6 +9859,11 @@ var replaceText = {
|
|
|
8918
9859
|
if (problem) issue(problem.path, problem.code, problem.message);
|
|
8919
9860
|
},
|
|
8920
9861
|
apply(operation2, context) {
|
|
9862
|
+
if (context.paragraph(operation2.target)?.paragraph.id === operation2.target)
|
|
9863
|
+
return replaceParagraphText.apply(
|
|
9864
|
+
{ ...operation2, op: "replaceParagraphText" },
|
|
9865
|
+
context
|
|
9866
|
+
);
|
|
8921
9867
|
const box = textBoxTarget(operation2.target, context);
|
|
8922
9868
|
if (box)
|
|
8923
9869
|
return textBoxReplaceText.apply(
|
|
@@ -8968,6 +9914,8 @@ function spanOf(operation2, previous) {
|
|
|
8968
9914
|
}
|
|
8969
9915
|
var setTextStyle = {
|
|
8970
9916
|
validate(operation2, context, issue) {
|
|
9917
|
+
if (context.paragraph(operation2.target)?.paragraph.id === operation2.target)
|
|
9918
|
+
return paragraphSetTextStyle.validate(operation2, context, issue);
|
|
8971
9919
|
if (textBoxTarget(operation2.target, context))
|
|
8972
9920
|
return textBoxSetTextStyle.validate(operation2, context, issue);
|
|
8973
9921
|
if (!textTarget(operation2.target, context, issue)) return;
|
|
@@ -8986,6 +9934,8 @@ var setTextStyle = {
|
|
|
8986
9934
|
);
|
|
8987
9935
|
},
|
|
8988
9936
|
apply(operation2, context) {
|
|
9937
|
+
if (context.paragraph(operation2.target)?.paragraph.id === operation2.target)
|
|
9938
|
+
return paragraphSetTextStyle.apply(operation2, context);
|
|
8989
9939
|
if (textBoxTarget(operation2.target, context))
|
|
8990
9940
|
return textBoxSetTextStyle.apply(operation2, context);
|
|
8991
9941
|
const target = textTarget(operation2.target, context);
|
|
@@ -9026,66 +9976,19 @@ function textTarget(target, context, issue = () => {
|
|
|
9026
9976
|
}
|
|
9027
9977
|
return { location, element };
|
|
9028
9978
|
}
|
|
9029
|
-
function validateScript(text, issue) {
|
|
9030
|
-
for (const character of text) {
|
|
9031
|
-
const code = character.codePointAt(0);
|
|
9032
|
-
if (code >= 1424 && code <= 2303 || code >= 64285 && code <= 65023 || code >= 65136 && code <= 65279) {
|
|
9033
|
-
issue(
|
|
9034
|
-
"/text",
|
|
9035
|
-
"unsupported-script",
|
|
9036
|
-
`Right-to-left text such as "${character}" cannot be edited yet`
|
|
9037
|
-
);
|
|
9038
|
-
return false;
|
|
9039
|
-
}
|
|
9040
|
-
}
|
|
9041
|
-
return true;
|
|
9042
|
-
}
|
|
9043
9979
|
function canKeepFont(context, target, text) {
|
|
9044
|
-
|
|
9045
|
-
|
|
9046
|
-
|
|
9047
|
-
|
|
9048
|
-
|
|
9049
|
-
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
}
|
|
9055
|
-
const coverage = fontCoverage(pdfium, font);
|
|
9056
|
-
if (!coverage) return false;
|
|
9057
|
-
for (const character of text) {
|
|
9058
|
-
const code = character.codePointAt(0);
|
|
9059
|
-
if (code !== 10 && code !== 32 && !coverage.drawable(code))
|
|
9060
|
-
return false;
|
|
9061
|
-
}
|
|
9062
|
-
return true;
|
|
9980
|
+
return context.readPage(target.location.pageIndex, (page) => {
|
|
9981
|
+
const object = context.pdfium.lib.FPDFPage_GetObject(
|
|
9982
|
+
page,
|
|
9983
|
+
target.location.indexes[0]
|
|
9984
|
+
);
|
|
9985
|
+
return fontCanRewrite(
|
|
9986
|
+
context.pdfium,
|
|
9987
|
+
context.pdfium.lib.FPDFTextObj_GetFont(object),
|
|
9988
|
+
text
|
|
9989
|
+
);
|
|
9063
9990
|
});
|
|
9064
9991
|
}
|
|
9065
|
-
function fontCoverage(pdfium, font) {
|
|
9066
|
-
const { lib } = pdfium;
|
|
9067
|
-
const size = pdfium.readNumbers(
|
|
9068
|
-
1,
|
|
9069
|
-
"i32",
|
|
9070
|
-
([out]) => lib.FPDFFont_GetFontData(font, 0, 0, out)
|
|
9071
|
-
)?.[0];
|
|
9072
|
-
if (!size) return void 0;
|
|
9073
|
-
const buffer = pdfium.malloc(size);
|
|
9074
|
-
try {
|
|
9075
|
-
const out = pdfium.malloc(4);
|
|
9076
|
-
try {
|
|
9077
|
-
if (!lib.FPDFFont_GetFontData(font, buffer, size, out)) return void 0;
|
|
9078
|
-
} finally {
|
|
9079
|
-
pdfium.free(out);
|
|
9080
|
-
}
|
|
9081
|
-
const data = pdfium.readBytes(buffer, size);
|
|
9082
|
-
const tag = String.fromCharCode(data[0], data[1], data[2], data[3]);
|
|
9083
|
-
const truetype = data[0] === 0 && data[1] === 1 && data[2] === 0 && data[3] === 0 || tag === "true";
|
|
9084
|
-
return truetype ? parseCmap(data) : void 0;
|
|
9085
|
-
} finally {
|
|
9086
|
-
pdfium.free(buffer);
|
|
9087
|
-
}
|
|
9088
|
-
}
|
|
9089
9992
|
function replaceInPlace(context, target, text) {
|
|
9090
9993
|
const { pdfium } = context;
|
|
9091
9994
|
const { lib } = pdfium;
|
|
@@ -9351,6 +10254,14 @@ var moveElement = {
|
|
|
9351
10254
|
validate(operation2, context, issue) {
|
|
9352
10255
|
const target = anyTarget(operation2.target, context, issue);
|
|
9353
10256
|
if (!target) return;
|
|
10257
|
+
if (target.element.kind === "paragraph") {
|
|
10258
|
+
issue(
|
|
10259
|
+
"/target",
|
|
10260
|
+
"unsupported-target",
|
|
10261
|
+
"Imported paragraphs cannot be moved"
|
|
10262
|
+
);
|
|
10263
|
+
return;
|
|
10264
|
+
}
|
|
9354
10265
|
if (operation2.to === void 0 === (operation2.by === void 0)) {
|
|
9355
10266
|
issue("", "one-of", "Give exactly one of `to` and `by`");
|
|
9356
10267
|
return;
|
|
@@ -9402,8 +10313,12 @@ var resizeElement = {
|
|
|
9402
10313
|
validate(operation2, context, issue) {
|
|
9403
10314
|
const target = anyTarget(operation2.target, context, issue);
|
|
9404
10315
|
if (!target) return;
|
|
9405
|
-
if (target.element.kind === "table") {
|
|
9406
|
-
issue(
|
|
10316
|
+
if (target.element.kind === "table" || target.element.kind === "paragraph") {
|
|
10317
|
+
issue(
|
|
10318
|
+
"/target",
|
|
10319
|
+
"unsupported-target",
|
|
10320
|
+
"Tables and imported paragraphs cannot be resized"
|
|
10321
|
+
);
|
|
9407
10322
|
return;
|
|
9408
10323
|
}
|
|
9409
10324
|
validateRect(
|
|
@@ -9457,10 +10372,16 @@ var deleteElement = {
|
|
|
9457
10372
|
},
|
|
9458
10373
|
apply(operation2, context) {
|
|
9459
10374
|
const { location } = anyTarget(operation2.target, context);
|
|
10375
|
+
const paragraph = context.paragraph(operation2.target)?.paragraph;
|
|
9460
10376
|
removeObjects(context, location);
|
|
9461
10377
|
return {
|
|
9462
10378
|
...changed(location, { overflow: false }),
|
|
9463
|
-
removedIds: [
|
|
10379
|
+
removedIds: [
|
|
10380
|
+
.../* @__PURE__ */ new Set([
|
|
10381
|
+
operation2.target,
|
|
10382
|
+
...paragraph?.id === operation2.target ? paragraph.memberIds : []
|
|
10383
|
+
])
|
|
10384
|
+
]
|
|
9464
10385
|
};
|
|
9465
10386
|
}
|
|
9466
10387
|
};
|
|
@@ -10500,6 +11421,7 @@ function referenceOf(operation2) {
|
|
|
10500
11421
|
return typeof target === "string" ? parseReference(target) : void 0;
|
|
10501
11422
|
}
|
|
10502
11423
|
var handlers = {
|
|
11424
|
+
replaceParagraphText,
|
|
10503
11425
|
insertTextBox,
|
|
10504
11426
|
replaceText,
|
|
10505
11427
|
setTextStyle,
|
|
@@ -10622,6 +11544,7 @@ var PdfEditDocument = class {
|
|
|
10622
11544
|
const createdIds = [];
|
|
10623
11545
|
const createdByOperation = [];
|
|
10624
11546
|
const removedIds = [];
|
|
11547
|
+
const textAnchorMigrations = [];
|
|
10625
11548
|
const changedPages = /* @__PURE__ */ new Set();
|
|
10626
11549
|
const warnings = [];
|
|
10627
11550
|
if (this.#batches === 0 && (this.#signatures > 0 || this.#features.length))
|
|
@@ -10646,6 +11569,8 @@ var PdfEditDocument = class {
|
|
|
10646
11569
|
createdIds.push(...result3.createdIds);
|
|
10647
11570
|
createdByOperation[operationIndex] = [...result3.createdIds];
|
|
10648
11571
|
removedIds.push(...result3.removedIds ?? []);
|
|
11572
|
+
for (const migration of result3.textAnchorMigrations ?? [])
|
|
11573
|
+
textAnchorMigrations.push({ ...migration, operationIndex });
|
|
10649
11574
|
for (const pageIndex of result3.changedPages) changedPages.add(pageIndex);
|
|
10650
11575
|
warnings.push(...result3.warnings);
|
|
10651
11576
|
});
|
|
@@ -10653,6 +11578,7 @@ var PdfEditDocument = class {
|
|
|
10653
11578
|
return {
|
|
10654
11579
|
createdIds,
|
|
10655
11580
|
removedIds,
|
|
11581
|
+
...textAnchorMigrations.length ? { textAnchorMigrations } : {},
|
|
10656
11582
|
changedPages: [...changedPages].sort((a, b) => a - b),
|
|
10657
11583
|
pageCount: this.pageCount,
|
|
10658
11584
|
warnings
|
|
@@ -10772,7 +11698,12 @@ var PdfEditDocument = class {
|
|
|
10772
11698
|
getElement(id) {
|
|
10773
11699
|
const pageIndex = this.#pageIndexOf(id);
|
|
10774
11700
|
if (pageIndex === void 0) return void 0;
|
|
10775
|
-
|
|
11701
|
+
const element = this.#elementsOf(pageIndex).find(
|
|
11702
|
+
(element2) => element2.id === id
|
|
11703
|
+
);
|
|
11704
|
+
if (element) return element;
|
|
11705
|
+
const target = this.#pages[pageIndex]?.paragraphs?.get(id);
|
|
11706
|
+
return target?.paragraph.id === id ? paragraphElement(target.paragraph) : void 0;
|
|
10776
11707
|
}
|
|
10777
11708
|
/** Elements under a point, top-most (drawn last) first. */
|
|
10778
11709
|
elementsAt(pageIndex, point) {
|
|
@@ -10802,20 +11733,40 @@ var PdfEditDocument = class {
|
|
|
10802
11733
|
});
|
|
10803
11734
|
return targets;
|
|
10804
11735
|
}
|
|
10805
|
-
/**
|
|
11736
|
+
/** Resolves the canonical imported paragraph, when its rows can be grouped safely. */
|
|
11737
|
+
textParagraph(elementId) {
|
|
11738
|
+
return this.#paragraphOf(elementId)?.paragraph;
|
|
11739
|
+
}
|
|
11740
|
+
#paragraphOf(id) {
|
|
11741
|
+
const pageIndex = this.#pageIndexOf(id);
|
|
11742
|
+
if (pageIndex === void 0) return void 0;
|
|
11743
|
+
this.#elementsOf(pageIndex);
|
|
11744
|
+
return this.#pages[pageIndex]?.paragraphs?.get(id);
|
|
11745
|
+
}
|
|
11746
|
+
/** Lines, glyph boxes and styles of a text, text box, paragraph or table element. */
|
|
10806
11747
|
textLayout(elementId) {
|
|
10807
11748
|
const pageIndex = this.#pageIndexOf(elementId);
|
|
10808
11749
|
if (pageIndex === void 0) return void 0;
|
|
10809
|
-
|
|
11750
|
+
const paragraph = this.#paragraphOf(elementId);
|
|
11751
|
+
return this.#scanText(pageIndex, (raw) => {
|
|
11752
|
+
const scan = paragraph?.paragraph.id === elementId ? this.#paragraphScan(raw, paragraph) : raw;
|
|
10810
11753
|
const element = scan.elements.find((entry) => entry.id === elementId);
|
|
10811
|
-
|
|
11754
|
+
const layout = element ? layoutOf(this.#pdfium, scan, element) : void 0;
|
|
11755
|
+
return layout && paragraph?.paragraph.id === elementId ? {
|
|
11756
|
+
...layout,
|
|
11757
|
+
lines: [...layout.lines].sort((a, b) => a.range.start.offset - b.range.start.offset).map((line) => ({
|
|
11758
|
+
...line,
|
|
11759
|
+
fontSize: paragraph.paragraph.textStyle.fontSize
|
|
11760
|
+
}))
|
|
11761
|
+
} : layout;
|
|
10812
11762
|
});
|
|
10813
11763
|
}
|
|
10814
11764
|
/** The browser face of the font a text or text box element is drawn in, see `TextFont`. */
|
|
10815
11765
|
textFont(elementId) {
|
|
10816
11766
|
const location = this.#locate(elementId);
|
|
10817
|
-
|
|
10818
|
-
|
|
11767
|
+
if (!location) return void 0;
|
|
11768
|
+
const kind = this.getElement(elementId)?.kind ?? (this.#paragraphOf(elementId)?.paragraph.id === elementId ? "paragraph" : void 0);
|
|
11769
|
+
if (kind !== "text" && kind !== "textBox" && kind !== "paragraph")
|
|
10819
11770
|
return void 0;
|
|
10820
11771
|
const { lib } = this.#pdfium;
|
|
10821
11772
|
return this.#withPage(location.pageIndex, (page) => {
|
|
@@ -10870,7 +11821,12 @@ var PdfEditDocument = class {
|
|
|
10870
11821
|
"The rendered page exceeds maxDecodedPixels",
|
|
10871
11822
|
{ details: { actual: pixels, limit: this.#limits.maxDecodedPixels } }
|
|
10872
11823
|
);
|
|
10873
|
-
const wanted = new Set(
|
|
11824
|
+
const wanted = new Set(
|
|
11825
|
+
elementIds.flatMap((id) => {
|
|
11826
|
+
const paragraph = this.#paragraphOf(id)?.paragraph;
|
|
11827
|
+
return paragraph?.id === id ? paragraph.memberIds : [id];
|
|
11828
|
+
})
|
|
11829
|
+
);
|
|
10874
11830
|
const records = this.#objectsOf(pageIndex, page);
|
|
10875
11831
|
const suppressed = [];
|
|
10876
11832
|
records.forEach((record, index) => {
|
|
@@ -10952,9 +11908,14 @@ var PdfEditDocument = class {
|
|
|
10952
11908
|
const pageIndex = this.#pageIndexOf(range.start.elementId);
|
|
10953
11909
|
if (pageIndex === void 0 || pageIndex !== this.#pageIndexOf(range.end.elementId))
|
|
10954
11910
|
return [];
|
|
11911
|
+
const paragraph = range.start.elementId === range.end.elementId ? this.#paragraphOf(range.start.elementId) : void 0;
|
|
10955
11912
|
return this.#scanText(
|
|
10956
11913
|
pageIndex,
|
|
10957
|
-
(scan) => rectsOf(
|
|
11914
|
+
(scan) => rectsOf(
|
|
11915
|
+
this.#pdfium,
|
|
11916
|
+
paragraph?.paragraph.id === range.start.elementId ? this.#paragraphScan(scan, paragraph) : scan,
|
|
11917
|
+
range
|
|
11918
|
+
)
|
|
10958
11919
|
);
|
|
10959
11920
|
}
|
|
10960
11921
|
dispose() {
|
|
@@ -10985,10 +11946,14 @@ var PdfEditDocument = class {
|
|
|
10985
11946
|
// part of the base, so a replay meets them and picks the same id.
|
|
10986
11947
|
newId: (pageIndex, suffix = "") => `${this.#unusedId(pageIndex, `${this.#pages[pageIndex].key}:n${stateId}.${operationIndex}.${created++}`)}${suffix}`,
|
|
10987
11948
|
withPage: (pageIndex, use) => this.#writePage(pageIndex, use),
|
|
11949
|
+
readPage: (pageIndex, use) => this.#withPage(pageIndex, use),
|
|
11950
|
+
paragraph: (id) => this.#paragraphOf(id),
|
|
11951
|
+
pageElements: (pageIndex) => this.#elementsOf(pageIndex),
|
|
10988
11952
|
appendObjects: (pageIndex, records) => {
|
|
10989
11953
|
const page = this.#pages[pageIndex];
|
|
10990
11954
|
page.objects = [...page.objects ?? [], ...records];
|
|
10991
11955
|
delete page.elements;
|
|
11956
|
+
delete page.paragraphs;
|
|
10992
11957
|
},
|
|
10993
11958
|
locate: (id) => this.#locate(id),
|
|
10994
11959
|
element: (id) => this.getElement(id),
|
|
@@ -11019,6 +11984,7 @@ var PdfEditDocument = class {
|
|
|
11019
11984
|
if (!page) return;
|
|
11020
11985
|
delete page.geometry;
|
|
11021
11986
|
delete page.elements;
|
|
11987
|
+
delete page.paragraphs;
|
|
11022
11988
|
},
|
|
11023
11989
|
spliceObjects: (pageIndex, start, count, records) => {
|
|
11024
11990
|
const page = this.#pages[pageIndex];
|
|
@@ -11026,12 +11992,16 @@ var PdfEditDocument = class {
|
|
|
11026
11992
|
objects.splice(start, count, ...records);
|
|
11027
11993
|
page.objects = objects;
|
|
11028
11994
|
delete page.elements;
|
|
11995
|
+
delete page.paragraphs;
|
|
11029
11996
|
}
|
|
11030
11997
|
};
|
|
11031
11998
|
}
|
|
11032
11999
|
/** Cached elements carry page indexes, which a structure change makes stale. */
|
|
11033
12000
|
#forgetElements() {
|
|
11034
|
-
for (const page of this.#pages)
|
|
12001
|
+
for (const page of this.#pages) {
|
|
12002
|
+
delete page.elements;
|
|
12003
|
+
delete page.paragraphs;
|
|
12004
|
+
}
|
|
11035
12005
|
}
|
|
11036
12006
|
#locate(id) {
|
|
11037
12007
|
const pageIndex = this.#pageIndexOf(id);
|
|
@@ -11045,7 +12015,14 @@ var PdfEditDocument = class {
|
|
|
11045
12015
|
if (record2.id === id) indexes.push(index);
|
|
11046
12016
|
});
|
|
11047
12017
|
const record = records[indexes[0] ?? -1];
|
|
11048
|
-
|
|
12018
|
+
if (record) return { pageIndex, indexes, record };
|
|
12019
|
+
const paragraph = this.#paragraphOf(id);
|
|
12020
|
+
const first = paragraph && records[paragraph.indexes[0] ?? -1];
|
|
12021
|
+
return paragraph?.paragraph.id === id && first ? {
|
|
12022
|
+
pageIndex,
|
|
12023
|
+
indexes: paragraph.indexes,
|
|
12024
|
+
record: { ...first, id, mark: paragraph.spec }
|
|
12025
|
+
} : void 0;
|
|
11049
12026
|
}
|
|
11050
12027
|
/** Loads a page, lets `use` change it, regenerates its content stream. */
|
|
11051
12028
|
#writePage(pageIndex, use) {
|
|
@@ -11067,6 +12044,7 @@ var PdfEditDocument = class {
|
|
|
11067
12044
|
}
|
|
11068
12045
|
);
|
|
11069
12046
|
delete this.#pages[pageIndex].elements;
|
|
12047
|
+
delete this.#pages[pageIndex].paragraphs;
|
|
11070
12048
|
return result3;
|
|
11071
12049
|
} finally {
|
|
11072
12050
|
lib.FPDF_ClosePage(page);
|
|
@@ -11093,7 +12071,22 @@ var PdfEditDocument = class {
|
|
|
11093
12071
|
geometry,
|
|
11094
12072
|
this.#objectsOf(pageIndex, page)
|
|
11095
12073
|
);
|
|
11096
|
-
record.
|
|
12074
|
+
record.paragraphs = discoverParagraphs(
|
|
12075
|
+
this.#pdfium,
|
|
12076
|
+
page,
|
|
12077
|
+
pageIndex,
|
|
12078
|
+
geometry,
|
|
12079
|
+
this.#objectsOf(pageIndex, page),
|
|
12080
|
+
elements,
|
|
12081
|
+
textPage,
|
|
12082
|
+
this.#measurer
|
|
12083
|
+
);
|
|
12084
|
+
record.elements = Object.freeze(
|
|
12085
|
+
elements.map((element) => {
|
|
12086
|
+
const paragraph = record.paragraphs?.get(element.id)?.paragraph;
|
|
12087
|
+
return paragraph && paragraph.id !== element.id ? { ...element, textEditingTarget: paragraph.id } : element;
|
|
12088
|
+
})
|
|
12089
|
+
);
|
|
11097
12090
|
return record.elements;
|
|
11098
12091
|
});
|
|
11099
12092
|
}
|
|
@@ -11206,6 +12199,27 @@ var PdfEditDocument = class {
|
|
|
11206
12199
|
};
|
|
11207
12200
|
return record.geometry;
|
|
11208
12201
|
}
|
|
12202
|
+
#paragraphScan(scan, target) {
|
|
12203
|
+
const paragraph = target.paragraph;
|
|
12204
|
+
if (paragraph.memberIds.includes(paragraph.id)) return scan;
|
|
12205
|
+
const members = new Map(
|
|
12206
|
+
paragraph.members.map((member) => [member.elementId, member])
|
|
12207
|
+
);
|
|
12208
|
+
return {
|
|
12209
|
+
...scan,
|
|
12210
|
+
elements: [
|
|
12211
|
+
...scan.elements.filter((element) => !members.has(element.id)),
|
|
12212
|
+
paragraphElement(paragraph)
|
|
12213
|
+
],
|
|
12214
|
+
offsets: scan.offsets.map((position) => {
|
|
12215
|
+
const member = position && members.get(position.elementId);
|
|
12216
|
+
return member && position ? {
|
|
12217
|
+
elementId: paragraph.id,
|
|
12218
|
+
offset: Math.min(member.end, member.start + position.offset)
|
|
12219
|
+
} : position;
|
|
12220
|
+
})
|
|
12221
|
+
};
|
|
12222
|
+
}
|
|
11209
12223
|
/** Loads a page with its text page and the character-to-element mapping. */
|
|
11210
12224
|
#scanText(pageIndex, use) {
|
|
11211
12225
|
return this.#withPage(pageIndex, (page, textPage, geometry) => {
|
|
@@ -11460,6 +12474,8 @@ function createPdfEditHandler(host) {
|
|
|
11460
12474
|
}
|
|
11461
12475
|
case "edit-text-layout":
|
|
11462
12476
|
return engine().textLayout(payload.id);
|
|
12477
|
+
case "edit-text-paragraph":
|
|
12478
|
+
return engine().textParagraph(payload.id);
|
|
11463
12479
|
case "edit-position-at": {
|
|
11464
12480
|
const { pageIndex, point } = payload;
|
|
11465
12481
|
return engine().positionAt(pageIndex, point);
|