@embedpdf/engine-services 3.0.0-next.10 → 3.0.0-next.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +737 -311
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -4
- package/dist/index.d.ts +59 -4
- package/dist/index.js +738 -313
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbortError, EMPTY_TRANSFER, EngineError, EngineErrorCode, NO_ANNOTATION_FLAGS, PAGE_INSERT_BLANK_MAX_COUNT, PDF_SUBTYPE_TO_CODE, PdfAnnotationSubtypeCode, UNKNOWN_WEAK_ANNOTATION_STATE, appearanceImpactOf, buildPageTextLayout, buildSnippet, charMapViolation, charRangeForTextOffsets, foldOptionsFor, foldText, invalidatesWeakIndexRefs, isValidPageObjectNumber, knownWeakAnnotationState, matchLiteral, matchRegex, normalizePdfRect, pdfQuadBounds, revisionTokensEqual, serializeError, shiftsExistingAnnotationIndices, sniffBinaryMetadata, subtypeFromCode, textSegmentsForRange, validateSearchQuery, wirePack } from "@embedpdf/engine-core/runtime";
|
|
1
|
+
import { AbortError, EMPTY_TRANSFER, EngineError, EngineErrorCode, NO_ANNOTATION_FLAGS, PAGE_INSERT_BLANK_MAX_COUNT, PDF_SUBTYPE_TO_CODE, PdfAnnotationSubtypeCode, UNKNOWN_WEAK_ANNOTATION_STATE, appearanceImpactOf, buildPageTextLayout, buildSnippet, charMapViolation, charRangeForTextOffsets, decodeSubmitFormFlags, foldOptionsFor, foldText, invalidatesWeakIndexRefs, isValidPageObjectNumber, knownWeakAnnotationState, matchLiteral, matchRegex, normalizePdfRect, pdfQuadBounds, revisionTokensEqual, serializeError, shiftsExistingAnnotationIndices, sniffBinaryMetadata, subtypeFromCode, textSegmentsForRange, validateSearchQuery, wirePack } from "@embedpdf/engine-core/runtime";
|
|
2
2
|
import { NULL_PTR } from "@embedpdf/engine-runtime";
|
|
3
3
|
//#region src/runtime/lifecycle/bootstrap.ts
|
|
4
4
|
const initialized = /* @__PURE__ */ new WeakSet();
|
|
@@ -1211,11 +1211,143 @@ function readI32(mem, ptr, byteOffset = 0) {
|
|
|
1211
1211
|
return Number(mem.peek(ptr, "i32", byteOffset));
|
|
1212
1212
|
}
|
|
1213
1213
|
//#endregion
|
|
1214
|
+
//#region src/features/destinations/destinationViewCodes.ts
|
|
1215
|
+
/**
|
|
1216
|
+
* `PDFDEST_VIEW_*` fit-type codes (public/fpdf_doc.h) — the shared
|
|
1217
|
+
* vocabulary of `FPDFDest_GetView` (read) and `EPDFDest_CreateView`
|
|
1218
|
+
* (write). XYZ is listed for completeness but never goes through
|
|
1219
|
+
* CreateView (it has its own null-aware constructor).
|
|
1220
|
+
*/
|
|
1221
|
+
const DEST_VIEW = {
|
|
1222
|
+
unknown: 0,
|
|
1223
|
+
xyz: 1,
|
|
1224
|
+
fit: 2,
|
|
1225
|
+
fitH: 3,
|
|
1226
|
+
fitV: 4,
|
|
1227
|
+
fitR: 5,
|
|
1228
|
+
fitB: 6,
|
|
1229
|
+
fitBH: 7,
|
|
1230
|
+
fitBV: 8
|
|
1231
|
+
};
|
|
1232
|
+
/** Wire destination kind → PDFDEST_VIEW code, for the non-XYZ kinds. */
|
|
1233
|
+
const VIEW_CODE_BY_KIND = {
|
|
1234
|
+
fit: DEST_VIEW.fit,
|
|
1235
|
+
fitH: DEST_VIEW.fitH,
|
|
1236
|
+
fitV: DEST_VIEW.fitV,
|
|
1237
|
+
fitR: DEST_VIEW.fitR,
|
|
1238
|
+
fitB: DEST_VIEW.fitB,
|
|
1239
|
+
fitBH: DEST_VIEW.fitBH,
|
|
1240
|
+
fitBV: DEST_VIEW.fitBV
|
|
1241
|
+
};
|
|
1242
|
+
//#endregion
|
|
1243
|
+
//#region src/features/destinations/readDestination.ts
|
|
1244
|
+
const MAX_VIEW_PARAMS = 4;
|
|
1245
|
+
/**
|
|
1246
|
+
* Materialise one explicit `PdfDestination` from a live `destPtr`. PDFium
|
|
1247
|
+
* already resolved named destinations before handing us the pointer, so
|
|
1248
|
+
* only explicit arrays arrive here (the rule `PdfDestination` documents).
|
|
1249
|
+
*
|
|
1250
|
+
* Returns `null` when the destination is unreadable: no visible indirect page
|
|
1251
|
+
* in the document, or an unknown fit type. Coordinates stay raw PDF user
|
|
1252
|
+
* space — no conversion at this layer.
|
|
1253
|
+
*
|
|
1254
|
+
* Shared by the link reader, `goto` action-node payloads, and the document
|
|
1255
|
+
* `openDestination`; the outline/bookmark port reuses it too.
|
|
1256
|
+
*/
|
|
1257
|
+
function readDestination(fn, mem, docPtr, destPtr) {
|
|
1258
|
+
const pageObjectNumber = fn.EPDFDest_GetPageObjectNumber(docPtr, destPtr);
|
|
1259
|
+
if (pageObjectNumber === 0) return null;
|
|
1260
|
+
const view = withScratchN(mem, [4, MAX_VIEW_PARAMS * 4], ([countPtr, paramsPtr]) => {
|
|
1261
|
+
const code = fn.FPDFDest_GetView(destPtr, countPtr, paramsPtr);
|
|
1262
|
+
const count = Math.min(readI32(mem, countPtr), MAX_VIEW_PARAMS);
|
|
1263
|
+
const params = [];
|
|
1264
|
+
for (let i = 0; i < count; i++) params.push(readF32(mem, paramsPtr, i * 4));
|
|
1265
|
+
return {
|
|
1266
|
+
code,
|
|
1267
|
+
params
|
|
1268
|
+
};
|
|
1269
|
+
});
|
|
1270
|
+
const at = (i) => i < view.params.length ? view.params[i] : null;
|
|
1271
|
+
switch (view.code) {
|
|
1272
|
+
case DEST_VIEW.xyz: return {
|
|
1273
|
+
kind: "xyz",
|
|
1274
|
+
pageObjectNumber,
|
|
1275
|
+
...readXyzLocation(fn, mem, destPtr)
|
|
1276
|
+
};
|
|
1277
|
+
case DEST_VIEW.fit: return {
|
|
1278
|
+
kind: "fit",
|
|
1279
|
+
pageObjectNumber
|
|
1280
|
+
};
|
|
1281
|
+
case DEST_VIEW.fitH: return {
|
|
1282
|
+
kind: "fitH",
|
|
1283
|
+
pageObjectNumber,
|
|
1284
|
+
top: at(0)
|
|
1285
|
+
};
|
|
1286
|
+
case DEST_VIEW.fitV: return {
|
|
1287
|
+
kind: "fitV",
|
|
1288
|
+
pageObjectNumber,
|
|
1289
|
+
left: at(0)
|
|
1290
|
+
};
|
|
1291
|
+
case DEST_VIEW.fitR:
|
|
1292
|
+
if (view.params.length < 4) return {
|
|
1293
|
+
kind: "fit",
|
|
1294
|
+
pageObjectNumber
|
|
1295
|
+
};
|
|
1296
|
+
return {
|
|
1297
|
+
kind: "fitR",
|
|
1298
|
+
pageObjectNumber,
|
|
1299
|
+
left: view.params[0],
|
|
1300
|
+
bottom: view.params[1],
|
|
1301
|
+
right: view.params[2],
|
|
1302
|
+
top: view.params[3]
|
|
1303
|
+
};
|
|
1304
|
+
case DEST_VIEW.fitB: return {
|
|
1305
|
+
kind: "fitB",
|
|
1306
|
+
pageObjectNumber
|
|
1307
|
+
};
|
|
1308
|
+
case DEST_VIEW.fitBH: return {
|
|
1309
|
+
kind: "fitBH",
|
|
1310
|
+
pageObjectNumber,
|
|
1311
|
+
top: at(0)
|
|
1312
|
+
};
|
|
1313
|
+
case DEST_VIEW.fitBV: return {
|
|
1314
|
+
kind: "fitBV",
|
|
1315
|
+
pageObjectNumber,
|
|
1316
|
+
left: at(0)
|
|
1317
|
+
};
|
|
1318
|
+
default: return null;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
/** `/XYZ` null-aware axes via `FPDFDest_GetLocationInPage` (FPDF_BOOL is 4 bytes). */
|
|
1322
|
+
function readXyzLocation(fn, mem, destPtr) {
|
|
1323
|
+
return withScratchN(mem, [
|
|
1324
|
+
4,
|
|
1325
|
+
4,
|
|
1326
|
+
4,
|
|
1327
|
+
4,
|
|
1328
|
+
4,
|
|
1329
|
+
4
|
|
1330
|
+
], ([hasLeft, hasTop, hasZoom, left, top, zoom]) => {
|
|
1331
|
+
if (!fn.FPDFDest_GetLocationInPage(destPtr, hasLeft, hasTop, hasZoom, left, top, zoom)) return {
|
|
1332
|
+
left: null,
|
|
1333
|
+
top: null,
|
|
1334
|
+
zoom: null
|
|
1335
|
+
};
|
|
1336
|
+
return {
|
|
1337
|
+
left: readI32(mem, hasLeft) ? readF32(mem, left) : null,
|
|
1338
|
+
top: readI32(mem, hasTop) ? readF32(mem, top) : null,
|
|
1339
|
+
zoom: readI32(mem, hasZoom) ? readF32(mem, zoom) : null
|
|
1340
|
+
};
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
//#endregion
|
|
1214
1344
|
//#region src/features/actions/ActionModelReader.ts
|
|
1215
1345
|
const DEFAULT_ACTION_READ_BUDGET = {
|
|
1216
1346
|
maxModels: 512,
|
|
1217
1347
|
maxNodes: 16384,
|
|
1218
|
-
maxScriptCodeUnits: 16e6
|
|
1348
|
+
maxScriptCodeUnits: 16e6,
|
|
1349
|
+
maxTargetEntries: 4096,
|
|
1350
|
+
maxPayloadCodeUnits: 262144
|
|
1219
1351
|
};
|
|
1220
1352
|
const ACTION_TYPE_BY_CODE = {
|
|
1221
1353
|
0: "unknown",
|
|
@@ -1243,22 +1375,20 @@ const WARNING_MALFORMED_NEXT = 2;
|
|
|
1243
1375
|
const WARNING_INCOMPLETE = 4;
|
|
1244
1376
|
const INVALID_NODE_U32 = 4294967295;
|
|
1245
1377
|
/** Decode one `EPDF_ACTION_TYPE_*` code — the shared vocabulary consumers
|
|
1246
|
-
*
|
|
1378
|
+
* use so action-shaped surfaces cannot drift. */
|
|
1247
1379
|
function actionTypeFromCode(code) {
|
|
1248
1380
|
return ACTION_TYPE_BY_CODE[code] ?? "unknown";
|
|
1249
1381
|
}
|
|
1250
|
-
/**
|
|
1251
|
-
*
|
|
1252
|
-
function isValidActionNodeId(raw) {
|
|
1253
|
-
return raw !== -1 && raw >>> 0 !== INVALID_NODE_U32;
|
|
1254
|
-
}
|
|
1255
|
-
/** Mutable aggregate budget shared by every action model in one read job. */
|
|
1382
|
+
/** Mutable aggregate budget shared by every action model in one read job.
|
|
1383
|
+
* Payload budgets are RESERVED before the backing buffer is allocated. */
|
|
1256
1384
|
var ActionReadBudgetTracker = class {
|
|
1257
1385
|
constructor(limits = DEFAULT_ACTION_READ_BUDGET) {
|
|
1258
1386
|
this.limits = limits;
|
|
1259
1387
|
_defineProperty(this, "models", 0);
|
|
1260
1388
|
_defineProperty(this, "nodes", 0);
|
|
1261
1389
|
_defineProperty(this, "scriptCodeUnits", 0);
|
|
1390
|
+
_defineProperty(this, "targetEntries", 0);
|
|
1391
|
+
_defineProperty(this, "payloadCodeUnits", 0);
|
|
1262
1392
|
}
|
|
1263
1393
|
addModel(nodeCount) {
|
|
1264
1394
|
this.models += 1;
|
|
@@ -1269,11 +1399,23 @@ var ActionReadBudgetTracker = class {
|
|
|
1269
1399
|
this.scriptCodeUnits += script.length;
|
|
1270
1400
|
this.assertWithinBudget();
|
|
1271
1401
|
}
|
|
1402
|
+
/** Charge target entries BEFORE the target array is walked. */
|
|
1403
|
+
reserveTargets(count) {
|
|
1404
|
+
this.targetEntries += count;
|
|
1405
|
+
this.assertWithinBudget();
|
|
1406
|
+
}
|
|
1407
|
+
/** Charge payload text BEFORE the scratch buffer for it is allocated. */
|
|
1408
|
+
reservePayloadBytes(length) {
|
|
1409
|
+
this.payloadCodeUnits += length;
|
|
1410
|
+
this.assertWithinBudget();
|
|
1411
|
+
}
|
|
1272
1412
|
assertWithinBudget() {
|
|
1273
|
-
if (this.models > this.limits.maxModels || this.nodes > this.limits.maxNodes || this.scriptCodeUnits > this.limits.maxScriptCodeUnits) throw new EngineError(EngineErrorCode.MalformedPdf, "aggregate PDF action read budget exceeded", { details: {
|
|
1413
|
+
if (this.models > this.limits.maxModels || this.nodes > this.limits.maxNodes || this.scriptCodeUnits > this.limits.maxScriptCodeUnits || this.targetEntries > this.limits.maxTargetEntries || this.payloadCodeUnits > this.limits.maxPayloadCodeUnits) throw new EngineError(EngineErrorCode.MalformedPdf, "aggregate PDF action read budget exceeded", { details: {
|
|
1274
1414
|
models: this.models,
|
|
1275
1415
|
nodes: this.nodes,
|
|
1276
1416
|
scriptCodeUnits: this.scriptCodeUnits,
|
|
1417
|
+
targetEntries: this.targetEntries,
|
|
1418
|
+
payloadCodeUnits: this.payloadCodeUnits,
|
|
1277
1419
|
limits: this.limits
|
|
1278
1420
|
} });
|
|
1279
1421
|
}
|
|
@@ -1281,8 +1423,17 @@ var ActionReadBudgetTracker = class {
|
|
|
1281
1423
|
/**
|
|
1282
1424
|
* Convert and close one detached native action model. This is the only
|
|
1283
1425
|
* native-model walker used by document, page, field, and annotation reads.
|
|
1426
|
+
*
|
|
1427
|
+
* `docPtr` resolves `goto` destinations (page identity + named-destination
|
|
1428
|
+
* lookup); every caller reads within an open document session.
|
|
1429
|
+
*
|
|
1430
|
+
* Payload rule: a node whose payload cannot be materialised (a goto without
|
|
1431
|
+
* a resolvable destination, a javascript node with no `/JS`, a withheld
|
|
1432
|
+
* target list) degrades to `{ type: 'unknown' }` with its original `/S` on
|
|
1433
|
+
* `subtype`, and the tree gains the `'payload-dropped'` warning — impossible
|
|
1434
|
+
* states stay unrepresentable while malformed documents stay readable.
|
|
1284
1435
|
*/
|
|
1285
|
-
function readActionModel(fn, mem, modelPtr, budget) {
|
|
1436
|
+
function readActionModel(fn, mem, docPtr, modelPtr, budget) {
|
|
1286
1437
|
if (modelPtr === NULL_PTR) return null;
|
|
1287
1438
|
try {
|
|
1288
1439
|
const nodeCount = fn.EPDFAction_GetNodeCount(modelPtr);
|
|
@@ -1292,13 +1443,61 @@ function readActionModel(fn, mem, modelPtr, budget) {
|
|
|
1292
1443
|
const incomplete = !fn.EPDFAction_IsComplete(modelPtr);
|
|
1293
1444
|
const rootId = normalizeOptionalNodeId(fn.EPDFAction_GetRootNode(modelPtr), nodeCount);
|
|
1294
1445
|
const visiting = /* @__PURE__ */ new Set();
|
|
1446
|
+
let payloadDropped = false;
|
|
1447
|
+
/** Probe the two-call length first and charge the budget BEFORE the
|
|
1448
|
+
* scratch buffer for the value is allocated. */
|
|
1449
|
+
const readPayloadString = (call) => {
|
|
1450
|
+
const length = call(NULL_PTR, 0);
|
|
1451
|
+
if (length <= 0) return null;
|
|
1452
|
+
budget.reservePayloadBytes(length);
|
|
1453
|
+
return readUtf8String(mem, call);
|
|
1454
|
+
};
|
|
1455
|
+
const readOutBool = (read) => withScratchN(mem, [4], ([outPtr]) => read(outPtr) ? readI32(mem, outPtr) !== 0 : null);
|
|
1456
|
+
const readTargetObjectNumber = (nodeId, index) => withScratchN(mem, [4], ([outPtr]) => {
|
|
1457
|
+
if (!fn.EPDFAction_GetNodeTargetObjectNumber(modelPtr, nodeId, index, outPtr)) return null;
|
|
1458
|
+
const value = readI32(mem, outPtr) >>> 0;
|
|
1459
|
+
return value === 0 ? null : value;
|
|
1460
|
+
});
|
|
1461
|
+
const readTargets = (nodeId, count) => {
|
|
1462
|
+
const targets = [];
|
|
1463
|
+
for (let index = 0; index < count; index++) {
|
|
1464
|
+
const name = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeTargetName(modelPtr, nodeId, index, buf, capacity));
|
|
1465
|
+
if (name !== null) {
|
|
1466
|
+
targets.push({
|
|
1467
|
+
kind: "name",
|
|
1468
|
+
name
|
|
1469
|
+
});
|
|
1470
|
+
continue;
|
|
1471
|
+
}
|
|
1472
|
+
const objectNumber = readTargetObjectNumber(nodeId, index);
|
|
1473
|
+
if (objectNumber === null) return null;
|
|
1474
|
+
targets.push({
|
|
1475
|
+
kind: "objectNumber",
|
|
1476
|
+
objectNumber
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
return targets;
|
|
1480
|
+
};
|
|
1481
|
+
const readResetFormState = (nodeId) => withScratchN(mem, [4, 4], ([hasFieldsPtr, excludePtr]) => {
|
|
1482
|
+
if (!fn.EPDFAction_GetNodeResetForm(modelPtr, nodeId, hasFieldsPtr, excludePtr)) return null;
|
|
1483
|
+
return {
|
|
1484
|
+
hasFields: readI32(mem, hasFieldsPtr) !== 0,
|
|
1485
|
+
exclude: readI32(mem, excludePtr) !== 0
|
|
1486
|
+
};
|
|
1487
|
+
});
|
|
1488
|
+
const readSubmitFormState = (nodeId) => withScratchN(mem, [4, 4], ([hasFieldsPtr, flagsPtr]) => {
|
|
1489
|
+
if (!fn.EPDFAction_GetNodeSubmitForm(modelPtr, nodeId, hasFieldsPtr, flagsPtr)) return null;
|
|
1490
|
+
return {
|
|
1491
|
+
hasFields: readI32(mem, hasFieldsPtr) !== 0,
|
|
1492
|
+
flags: readI32(mem, flagsPtr) >>> 0
|
|
1493
|
+
};
|
|
1494
|
+
});
|
|
1295
1495
|
const readNode = (nodeId) => {
|
|
1296
1496
|
if (visiting.has(nodeId)) throw malformedActionModel("native action model contains a cycle", { nodeId });
|
|
1297
1497
|
visiting.add(nodeId);
|
|
1298
1498
|
try {
|
|
1499
|
+
const type = actionTypeFromCode(fn.EPDFAction_GetNodeType(modelPtr, nodeId));
|
|
1299
1500
|
const subtype = readUtf8String(mem, (buf, capacity) => fn.EPDFAction_GetNodeSubtype(modelPtr, nodeId, buf, capacity)) ?? "";
|
|
1300
|
-
const script = fn.EPDFAction_NodeHasJavaScript(modelPtr, nodeId) ? readUtf16String(mem, (buf, capacity) => fn.EPDFAction_GetNodeJavaScript(modelPtr, nodeId, buf, capacity)) ?? "" : void 0;
|
|
1301
|
-
if (script !== void 0) budget.addScript(script);
|
|
1302
1501
|
const nextCount = fn.EPDFAction_GetNextCount(modelPtr, nodeId);
|
|
1303
1502
|
if (!Number.isInteger(nextCount) || nextCount < 0) throw malformedActionModel("invalid action child count", {
|
|
1304
1503
|
nodeId,
|
|
@@ -1309,21 +1508,157 @@ function readActionModel(fn, mem, modelPtr, budget) {
|
|
|
1309
1508
|
const childId = normalizeNodeId(fn.EPDFAction_GetNextAt(modelPtr, nodeId, index), nodeCount);
|
|
1310
1509
|
next.push(readNode(childId));
|
|
1311
1510
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1511
|
+
const degraded = () => {
|
|
1512
|
+
payloadDropped = true;
|
|
1513
|
+
return {
|
|
1514
|
+
type: "unknown",
|
|
1515
|
+
subtype,
|
|
1516
|
+
next
|
|
1517
|
+
};
|
|
1317
1518
|
};
|
|
1519
|
+
switch (type) {
|
|
1520
|
+
case "javascript": {
|
|
1521
|
+
if (!fn.EPDFAction_NodeHasJavaScript(modelPtr, nodeId)) return degraded();
|
|
1522
|
+
const script = readUtf16String(mem, (buf, capacity) => fn.EPDFAction_GetNodeJavaScript(modelPtr, nodeId, buf, capacity)) ?? "";
|
|
1523
|
+
budget.addScript(script);
|
|
1524
|
+
return {
|
|
1525
|
+
type,
|
|
1526
|
+
subtype,
|
|
1527
|
+
script,
|
|
1528
|
+
next
|
|
1529
|
+
};
|
|
1530
|
+
}
|
|
1531
|
+
case "rendition": {
|
|
1532
|
+
if (!fn.EPDFAction_NodeHasJavaScript(modelPtr, nodeId)) return {
|
|
1533
|
+
type,
|
|
1534
|
+
subtype,
|
|
1535
|
+
next
|
|
1536
|
+
};
|
|
1537
|
+
const script = readUtf16String(mem, (buf, capacity) => fn.EPDFAction_GetNodeJavaScript(modelPtr, nodeId, buf, capacity)) ?? "";
|
|
1538
|
+
budget.addScript(script);
|
|
1539
|
+
return {
|
|
1540
|
+
type,
|
|
1541
|
+
subtype,
|
|
1542
|
+
script,
|
|
1543
|
+
next
|
|
1544
|
+
};
|
|
1545
|
+
}
|
|
1546
|
+
case "goto": {
|
|
1547
|
+
const destPtr = fn.EPDFAction_GetNodeDest(docPtr, modelPtr, nodeId);
|
|
1548
|
+
const destination = destPtr !== NULL_PTR ? readDestination(fn, mem, docPtr, destPtr) : null;
|
|
1549
|
+
return destination ? {
|
|
1550
|
+
type,
|
|
1551
|
+
subtype,
|
|
1552
|
+
destination,
|
|
1553
|
+
next
|
|
1554
|
+
} : degraded();
|
|
1555
|
+
}
|
|
1556
|
+
case "uri": {
|
|
1557
|
+
const uri = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeURI(docPtr, modelPtr, nodeId, buf, capacity));
|
|
1558
|
+
if (uri === null) return degraded();
|
|
1559
|
+
return {
|
|
1560
|
+
type,
|
|
1561
|
+
subtype,
|
|
1562
|
+
uri,
|
|
1563
|
+
isMap: readOutBool((outPtr) => fn.EPDFAction_GetNodeURIIsMap(modelPtr, nodeId, outPtr)) ?? false,
|
|
1564
|
+
next
|
|
1565
|
+
};
|
|
1566
|
+
}
|
|
1567
|
+
case "named": {
|
|
1568
|
+
const name = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeName(modelPtr, nodeId, buf, capacity));
|
|
1569
|
+
return name === null ? degraded() : {
|
|
1570
|
+
type,
|
|
1571
|
+
subtype,
|
|
1572
|
+
name,
|
|
1573
|
+
next
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
case "hide": {
|
|
1577
|
+
const count = fn.EPDFAction_GetNodeTargetCount(modelPtr, nodeId);
|
|
1578
|
+
if (!Number.isInteger(count) || count < 0) return degraded();
|
|
1579
|
+
budget.reserveTargets(count);
|
|
1580
|
+
const targets = readTargets(nodeId, count);
|
|
1581
|
+
if (targets === null) return degraded();
|
|
1582
|
+
return {
|
|
1583
|
+
type,
|
|
1584
|
+
subtype,
|
|
1585
|
+
targets,
|
|
1586
|
+
hide: readOutBool((outPtr) => fn.EPDFAction_GetNodeHideFlag(modelPtr, nodeId, outPtr)) ?? true,
|
|
1587
|
+
next
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
case "reset-form": {
|
|
1591
|
+
const state = readResetFormState(nodeId);
|
|
1592
|
+
const count = fn.EPDFAction_GetNodeTargetCount(modelPtr, nodeId);
|
|
1593
|
+
if (state === null || !Number.isInteger(count) || count < 0) return degraded();
|
|
1594
|
+
budget.reserveTargets(count);
|
|
1595
|
+
const fields = state.hasFields ? readTargets(nodeId, count) : null;
|
|
1596
|
+
if (state.hasFields && fields === null) return degraded();
|
|
1597
|
+
return {
|
|
1598
|
+
type,
|
|
1599
|
+
subtype,
|
|
1600
|
+
fields,
|
|
1601
|
+
exclude: state.exclude,
|
|
1602
|
+
next
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
case "submit-form": {
|
|
1606
|
+
if (typeof fn.EPDFAction_GetNodeSubmitForm !== "function") return {
|
|
1607
|
+
type,
|
|
1608
|
+
subtype,
|
|
1609
|
+
next
|
|
1610
|
+
};
|
|
1611
|
+
const state = readSubmitFormState(nodeId);
|
|
1612
|
+
if (state === null) return degraded();
|
|
1613
|
+
const url = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeSubmitFormURL(modelPtr, nodeId, buf, capacity));
|
|
1614
|
+
if (url === null) return degraded();
|
|
1615
|
+
const count = fn.EPDFAction_GetNodeTargetCount(modelPtr, nodeId);
|
|
1616
|
+
if (!Number.isInteger(count) || count < 0) return degraded();
|
|
1617
|
+
budget.reserveTargets(count);
|
|
1618
|
+
const fields = state.hasFields ? readTargets(nodeId, count) : null;
|
|
1619
|
+
if (state.hasFields && fields === null) return degraded();
|
|
1620
|
+
const charSet = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeSubmitFormCharSet(modelPtr, nodeId, buf, capacity));
|
|
1621
|
+
return {
|
|
1622
|
+
type,
|
|
1623
|
+
subtype,
|
|
1624
|
+
payload: {
|
|
1625
|
+
url,
|
|
1626
|
+
fields,
|
|
1627
|
+
flags: decodeSubmitFormFlags(state.flags),
|
|
1628
|
+
...charSet === null ? {} : { charSet }
|
|
1629
|
+
},
|
|
1630
|
+
next
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
case "goto-remote":
|
|
1634
|
+
case "goto-embedded":
|
|
1635
|
+
case "launch": {
|
|
1636
|
+
const filePath = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeFilePath(modelPtr, nodeId, buf, capacity));
|
|
1637
|
+
return filePath === null ? degraded() : {
|
|
1638
|
+
type,
|
|
1639
|
+
subtype,
|
|
1640
|
+
filePath,
|
|
1641
|
+
next
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
default: return {
|
|
1645
|
+
type,
|
|
1646
|
+
subtype,
|
|
1647
|
+
next
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1318
1650
|
} finally {
|
|
1319
1651
|
visiting.delete(nodeId);
|
|
1320
1652
|
}
|
|
1321
1653
|
};
|
|
1654
|
+
const root = rootId === null ? null : readNode(rootId);
|
|
1655
|
+
const warnings = warningsFromFlags(warningFlags, incomplete);
|
|
1656
|
+
if (payloadDropped) warnings.push("payload-dropped");
|
|
1322
1657
|
return {
|
|
1323
|
-
root
|
|
1658
|
+
root,
|
|
1324
1659
|
incomplete,
|
|
1325
1660
|
warningFlags,
|
|
1326
|
-
warnings
|
|
1661
|
+
warnings
|
|
1327
1662
|
};
|
|
1328
1663
|
} finally {
|
|
1329
1664
|
fn.EPDFAction_CloseModel(modelPtr);
|
|
@@ -1396,15 +1731,16 @@ var PagesReader = class {
|
|
|
1396
1731
|
});
|
|
1397
1732
|
return {
|
|
1398
1733
|
pageCount: pages.length,
|
|
1399
|
-
pages
|
|
1734
|
+
pages,
|
|
1735
|
+
namedPages: readNamedPages(fn, mem, docPtr)
|
|
1400
1736
|
};
|
|
1401
1737
|
});
|
|
1402
1738
|
}
|
|
1403
1739
|
};
|
|
1404
1740
|
function readPageActions(fn, mem, docPtr, pageObjectNumber, budget) {
|
|
1405
1741
|
const actions = {};
|
|
1406
|
-
const open = readActionModel(fn, mem, fn.EPDFDoc_GetPageActionModel(docPtr, pageObjectNumber, 0), budget);
|
|
1407
|
-
const close = readActionModel(fn, mem, fn.EPDFDoc_GetPageActionModel(docPtr, pageObjectNumber, 1), budget);
|
|
1742
|
+
const open = readActionModel(fn, mem, docPtr, fn.EPDFDoc_GetPageActionModel(docPtr, pageObjectNumber, 0), budget);
|
|
1743
|
+
const close = readActionModel(fn, mem, docPtr, fn.EPDFDoc_GetPageActionModel(docPtr, pageObjectNumber, 1), budget);
|
|
1408
1744
|
if (open) actions.open = open;
|
|
1409
1745
|
if (close) actions.close = close;
|
|
1410
1746
|
return open || close ? actions : void 0;
|
|
@@ -1461,6 +1797,41 @@ function readUserUnit(fn, mem, docPtr, index, userUnitPtr) {
|
|
|
1461
1797
|
function readLabel(fn, mem, docPtr, index) {
|
|
1462
1798
|
return readUtf16String(mem, (buf, capacity) => fn.FPDF_GetPageLabel(docPtr, index, buf, capacity), null) || null;
|
|
1463
1799
|
}
|
|
1800
|
+
const NAMED_PAGE_TREES = [0, 1];
|
|
1801
|
+
const NAMED_PAGE_KIND_PAGE = 0;
|
|
1802
|
+
const NAMED_PAGE_KIND_TEMPLATE = 1;
|
|
1803
|
+
/**
|
|
1804
|
+
* The catalog's `/Names /Pages` and `/Names /Templates` registrations, in
|
|
1805
|
+
* tree order, each value classified by the fork (page / template /
|
|
1806
|
+
* dangling). Page-identity data like `label`, so it ships inside the same
|
|
1807
|
+
* snapshot — a registration is only meaningful against the page set that
|
|
1808
|
+
* contains its target.
|
|
1809
|
+
*/
|
|
1810
|
+
function readNamedPages(fn, mem, docPtr) {
|
|
1811
|
+
const entries = [];
|
|
1812
|
+
withScratchN(mem, [4, 4], ([objNumPtr, kindPtr]) => {
|
|
1813
|
+
for (const tree of NAMED_PAGE_TREES) {
|
|
1814
|
+
const count = fn.EPDFDoc_GetNamedPageCount(docPtr, tree);
|
|
1815
|
+
for (let index = 0; index < count; index++) {
|
|
1816
|
+
const name = readUtf16String(mem, (buf, capacity) => fn.EPDFDoc_GetNamedPageAt(docPtr, tree, index, buf, capacity, objNumPtr, kindPtr), "");
|
|
1817
|
+
if (name === null) continue;
|
|
1818
|
+
const objectNumber = Number(mem.peek(objNumPtr, "i32")) >>> 0;
|
|
1819
|
+
const kind = Number(mem.peek(kindPtr, "i32"));
|
|
1820
|
+
entries.push({
|
|
1821
|
+
name,
|
|
1822
|
+
target: kind === NAMED_PAGE_KIND_PAGE ? {
|
|
1823
|
+
kind: "page",
|
|
1824
|
+
pageObjectNumber: objectNumber
|
|
1825
|
+
} : kind === NAMED_PAGE_KIND_TEMPLATE ? {
|
|
1826
|
+
kind: "template",
|
|
1827
|
+
objectNumber
|
|
1828
|
+
} : { kind: "dangling" }
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
});
|
|
1833
|
+
return entries;
|
|
1834
|
+
}
|
|
1464
1835
|
//#endregion
|
|
1465
1836
|
//#region src/features/pages/PagesMutator.ts
|
|
1466
1837
|
/**
|
|
@@ -1608,6 +1979,38 @@ var PagesMutator = class {
|
|
|
1608
1979
|
cache: null
|
|
1609
1980
|
};
|
|
1610
1981
|
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Register `name` → page in `/Names /Pages` (create, or replace what the
|
|
1984
|
+
* key points at); with `replace`, drop that other key first — a rename as
|
|
1985
|
+
* one job. Named pages are LAYOUT: page identity and order are untouched
|
|
1986
|
+
* (no registry refresh, no revision bumps) and the fresh snapshot is
|
|
1987
|
+
* returned like `move()`.
|
|
1988
|
+
*/
|
|
1989
|
+
setName(input, signal) {
|
|
1990
|
+
throwIfAborted(signal);
|
|
1991
|
+
if (input.name.length === 0) throw new EngineError(EngineErrorCode.InvalidArg, "pages.setName requires a non-empty name");
|
|
1992
|
+
const { fn, mem } = this.runtime;
|
|
1993
|
+
const docPtr = this.session.requireDocPtr();
|
|
1994
|
+
this.session.recordByObjectNumber(input.pageObjectNumber);
|
|
1995
|
+
if (input.replace !== void 0 && input.replace !== input.name && input.replace.length > 0) writeUtf16String(mem, input.replace, (ptr) => fn.EPDFDoc_RemoveNamedPage(docPtr, ptr));
|
|
1996
|
+
if (!writeUtf16String(mem, input.name, (ptr) => fn.EPDFDoc_SetNamedPage(docPtr, ptr, input.pageObjectNumber))) throw new EngineError(EngineErrorCode.Unknown, `EPDFDoc_SetNamedPage rejected '${input.name}' for page ${input.pageObjectNumber}`);
|
|
1997
|
+
return {
|
|
1998
|
+
layout: new PagesReader(this.runtime, this.session).read(signal),
|
|
1999
|
+
cache: null
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
/** Remove one `/Names /Pages` registration; the page stays. */
|
|
2003
|
+
removeName(input, signal) {
|
|
2004
|
+
throwIfAborted(signal);
|
|
2005
|
+
if (input.name.length === 0) throw new EngineError(EngineErrorCode.InvalidArg, "pages.removeName requires a non-empty name");
|
|
2006
|
+
const { fn, mem } = this.runtime;
|
|
2007
|
+
const docPtr = this.session.requireDocPtr();
|
|
2008
|
+
if (!writeUtf16String(mem, input.name, (ptr) => fn.EPDFDoc_RemoveNamedPage(docPtr, ptr))) throw new EngineError(EngineErrorCode.NotFound, `pages.removeName: no /Names /Pages registration '${input.name}'`);
|
|
2009
|
+
return {
|
|
2010
|
+
layout: new PagesReader(this.runtime, this.session).read(signal),
|
|
2011
|
+
cache: null
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
1611
2014
|
/** Shared input check: non-empty, no duplicate PONs. */
|
|
1612
2015
|
requireUniquePons(op, pageObjectNumbers) {
|
|
1613
2016
|
if (pageObjectNumbers.length === 0) throw new EngineError(EngineErrorCode.InvalidArg, `${op} requires at least one page`);
|
|
@@ -1620,7 +2023,7 @@ var PagesMutator = class {
|
|
|
1620
2023
|
};
|
|
1621
2024
|
//#endregion
|
|
1622
2025
|
//#region src/features/pages/PagesExtractor.ts
|
|
1623
|
-
const FPDF_NO_INCREMENTAL$
|
|
2026
|
+
const FPDF_NO_INCREMENTAL$2 = 2;
|
|
1624
2027
|
/**
|
|
1625
2028
|
* Export a subset of pages as a standalone PDF. A READ over the session:
|
|
1626
2029
|
* `FPDF_ImportPagesByIndex` copies pages into a scratch document, so the
|
|
@@ -1659,7 +2062,7 @@ var PagesExtractor = class {
|
|
|
1659
2062
|
for (let i = 0; i < indices.length; i++) mem.poke(idxPtr, "i32", indices[i], 4 * i);
|
|
1660
2063
|
if (!fn.FPDF_ImportPagesByIndex(destPtr, srcPtr, idxPtr, indices.length, 0)) throw new EngineError(EngineErrorCode.Unknown, `FPDF_ImportPagesByIndex rejected the request (indices=[${indices.join(",")}])`);
|
|
1661
2064
|
mem.poke(sizePtr, "i32", 0);
|
|
1662
|
-
pdfPtr = fn.EPDF_SaveDocumentToOwnedBuffer(destPtr, FPDF_NO_INCREMENTAL$
|
|
2065
|
+
pdfPtr = fn.EPDF_SaveDocumentToOwnedBuffer(destPtr, FPDF_NO_INCREMENTAL$2, sizePtr);
|
|
1663
2066
|
const size = Number(mem.peek(sizePtr, "i32"));
|
|
1664
2067
|
if (!pdfPtr || size <= 0) throw new EngineError(EngineErrorCode.DocOpenFailed, "failed to save extracted pages");
|
|
1665
2068
|
const bytes = mem.readBytes(pdfPtr, size);
|
|
@@ -2211,6 +2614,13 @@ function readQuadPoints(fn, mem, annotPtr) {
|
|
|
2211
2614
|
return out;
|
|
2212
2615
|
});
|
|
2213
2616
|
}
|
|
2617
|
+
/**
|
|
2618
|
+
* `/Name` as text, whatever its value (`EPDFAnnot_GetName`): a standard
|
|
2619
|
+
* icon/stamp name or a custom identifier. `null` when absent.
|
|
2620
|
+
*/
|
|
2621
|
+
function readAnnotName(fn, mem, annotPtr) {
|
|
2622
|
+
return readUtf8String(mem, (buf, capacity) => fn.EPDFAnnot_GetName(annotPtr, buf, capacity));
|
|
2623
|
+
}
|
|
2214
2624
|
//#endregion
|
|
2215
2625
|
//#region src/features/annotations/internal/read/readAnnotationTransformMetadata.ts
|
|
2216
2626
|
/**
|
|
@@ -2460,29 +2870,29 @@ function normalizeChecksum(raw) {
|
|
|
2460
2870
|
//#endregion
|
|
2461
2871
|
//#region src/features/annotations/internal/annotationIcon.ts
|
|
2462
2872
|
/**
|
|
2463
|
-
* `/Name` icon ↔
|
|
2464
|
-
*
|
|
2465
|
-
*
|
|
2466
|
-
*
|
|
2467
|
-
*
|
|
2468
|
-
*/
|
|
2469
|
-
const
|
|
2470
|
-
comment:
|
|
2471
|
-
key:
|
|
2472
|
-
note:
|
|
2473
|
-
help:
|
|
2474
|
-
"new-paragraph":
|
|
2475
|
-
paragraph:
|
|
2476
|
-
insert:
|
|
2873
|
+
* `/Name` icon vocabulary ↔ PDF name mapping for text and file-attachment
|
|
2874
|
+
* annotations (ISO 32000-2 tables 175 and 184). The wire speaks the
|
|
2875
|
+
* kebab-case ids; `EPDFAnnot_SetName` / `EPDFAnnot_GetName` speak the PDF
|
|
2876
|
+
* names. An unknown PDF name reads as the subtype's default (the reader
|
|
2877
|
+
* draws the default glyph for names it does not know — spec behavior).
|
|
2878
|
+
*/
|
|
2879
|
+
const NOTE_ICON_TO_NAME = Object.freeze({
|
|
2880
|
+
comment: "Comment",
|
|
2881
|
+
key: "Key",
|
|
2882
|
+
note: "Note",
|
|
2883
|
+
help: "Help",
|
|
2884
|
+
"new-paragraph": "NewParagraph",
|
|
2885
|
+
paragraph: "Paragraph",
|
|
2886
|
+
insert: "Insert"
|
|
2477
2887
|
});
|
|
2478
|
-
const
|
|
2479
|
-
const
|
|
2480
|
-
graph:
|
|
2481
|
-
"push-pin":
|
|
2482
|
-
paperclip:
|
|
2483
|
-
tag:
|
|
2888
|
+
const NOTE_NAME_TO_ICON = Object.freeze(Object.fromEntries(Object.entries(NOTE_ICON_TO_NAME).map(([icon, name]) => [name, icon])));
|
|
2889
|
+
const FILE_ICON_TO_NAME = Object.freeze({
|
|
2890
|
+
graph: "Graph",
|
|
2891
|
+
"push-pin": "PushPin",
|
|
2892
|
+
paperclip: "Paperclip",
|
|
2893
|
+
tag: "Tag"
|
|
2484
2894
|
});
|
|
2485
|
-
const
|
|
2895
|
+
const FILE_NAME_TO_ICON = Object.freeze(Object.fromEntries(Object.entries(FILE_ICON_TO_NAME).map(([icon, name]) => [name, icon])));
|
|
2486
2896
|
//#endregion
|
|
2487
2897
|
//#region src/features/annotations/internal/read/readFileAttachmentAnnotation.ts
|
|
2488
2898
|
/** Default `/C` — matches the generator's default icon fill and the writer default. */
|
|
@@ -2504,7 +2914,7 @@ function readFileAttachment(fn, mem, annotPtr, base) {
|
|
|
2504
2914
|
const color = readAnnotColor(fn, mem, annotPtr) ?? { ...DEFAULT_FILE_ATTACHMENT_COLOR$1 };
|
|
2505
2915
|
const ca = readAnnotOpacity(fn, mem, annotPtr);
|
|
2506
2916
|
const opacity = ca == null ? 1 : Math.max(0, Math.min(1, ca));
|
|
2507
|
-
const icon =
|
|
2917
|
+
const icon = FILE_NAME_TO_ICON[readAnnotName(fn, mem, annotPtr) ?? ""] ?? DEFAULT_FILE_ATTACHMENT_ICON;
|
|
2508
2918
|
const attachmentPtr = fn.FPDFAnnot_GetFileAttachment(annotPtr);
|
|
2509
2919
|
const file = attachmentPtr ? readAttachmentFileInfo(fn, mem, attachmentPtr) : { name: "" };
|
|
2510
2920
|
return {
|
|
@@ -2822,167 +3232,67 @@ function readLine(fn, mem, annotPtr, base) {
|
|
|
2822
3232
|
};
|
|
2823
3233
|
}
|
|
2824
3234
|
//#endregion
|
|
2825
|
-
//#region src/features/annotations/internal/destinationViewCodes.ts
|
|
2826
|
-
/**
|
|
2827
|
-
* `PDFDEST_VIEW_*` fit-type codes (public/fpdf_doc.h) — the shared
|
|
2828
|
-
* vocabulary of `FPDFDest_GetView` (read) and `EPDFDest_CreateView`
|
|
2829
|
-
* (write). XYZ is listed for completeness but never goes through
|
|
2830
|
-
* CreateView (it has its own null-aware constructor).
|
|
2831
|
-
*/
|
|
2832
|
-
const DEST_VIEW = {
|
|
2833
|
-
unknown: 0,
|
|
2834
|
-
xyz: 1,
|
|
2835
|
-
fit: 2,
|
|
2836
|
-
fitH: 3,
|
|
2837
|
-
fitV: 4,
|
|
2838
|
-
fitR: 5,
|
|
2839
|
-
fitB: 6,
|
|
2840
|
-
fitBH: 7,
|
|
2841
|
-
fitBV: 8
|
|
2842
|
-
};
|
|
2843
|
-
/** Wire destination kind → PDFDEST_VIEW code, for the non-XYZ kinds. */
|
|
2844
|
-
const VIEW_CODE_BY_KIND = {
|
|
2845
|
-
fit: DEST_VIEW.fit,
|
|
2846
|
-
fitH: DEST_VIEW.fitH,
|
|
2847
|
-
fitV: DEST_VIEW.fitV,
|
|
2848
|
-
fitR: DEST_VIEW.fitR,
|
|
2849
|
-
fitB: DEST_VIEW.fitB,
|
|
2850
|
-
fitBH: DEST_VIEW.fitBH,
|
|
2851
|
-
fitBV: DEST_VIEW.fitBV
|
|
2852
|
-
};
|
|
2853
|
-
//#endregion
|
|
2854
|
-
//#region src/features/annotations/internal/read/readDestination.ts
|
|
2855
|
-
const MAX_VIEW_PARAMS = 4;
|
|
2856
|
-
/**
|
|
2857
|
-
* Materialise one explicit `PdfDestination` from a live `destPtr`. PDFium
|
|
2858
|
-
* already resolved named destinations before handing us the pointer, so
|
|
2859
|
-
* only explicit arrays arrive here (the rule `PdfDestination` documents).
|
|
2860
|
-
*
|
|
2861
|
-
* Returns `null` when the destination is unreadable: no visible indirect page
|
|
2862
|
-
* in the document, or an unknown fit type. Coordinates stay raw PDF user
|
|
2863
|
-
* space — no conversion at this layer.
|
|
2864
|
-
*
|
|
2865
|
-
* Shared by the link reader today; the outline/bookmark port reuses it.
|
|
2866
|
-
*/
|
|
2867
|
-
function readDestination(fn, mem, docPtr, destPtr) {
|
|
2868
|
-
const pageObjectNumber = fn.EPDFDest_GetPageObjectNumber(docPtr, destPtr);
|
|
2869
|
-
if (pageObjectNumber === 0) return null;
|
|
2870
|
-
const view = withScratchN(mem, [4, MAX_VIEW_PARAMS * 4], ([countPtr, paramsPtr]) => {
|
|
2871
|
-
const code = fn.FPDFDest_GetView(destPtr, countPtr, paramsPtr);
|
|
2872
|
-
const count = Math.min(readI32(mem, countPtr), MAX_VIEW_PARAMS);
|
|
2873
|
-
const params = [];
|
|
2874
|
-
for (let i = 0; i < count; i++) params.push(readF32(mem, paramsPtr, i * 4));
|
|
2875
|
-
return {
|
|
2876
|
-
code,
|
|
2877
|
-
params
|
|
2878
|
-
};
|
|
2879
|
-
});
|
|
2880
|
-
const at = (i) => i < view.params.length ? view.params[i] : null;
|
|
2881
|
-
switch (view.code) {
|
|
2882
|
-
case DEST_VIEW.xyz: return {
|
|
2883
|
-
kind: "xyz",
|
|
2884
|
-
pageObjectNumber,
|
|
2885
|
-
...readXyzLocation(fn, mem, destPtr)
|
|
2886
|
-
};
|
|
2887
|
-
case DEST_VIEW.fit: return {
|
|
2888
|
-
kind: "fit",
|
|
2889
|
-
pageObjectNumber
|
|
2890
|
-
};
|
|
2891
|
-
case DEST_VIEW.fitH: return {
|
|
2892
|
-
kind: "fitH",
|
|
2893
|
-
pageObjectNumber,
|
|
2894
|
-
top: at(0)
|
|
2895
|
-
};
|
|
2896
|
-
case DEST_VIEW.fitV: return {
|
|
2897
|
-
kind: "fitV",
|
|
2898
|
-
pageObjectNumber,
|
|
2899
|
-
left: at(0)
|
|
2900
|
-
};
|
|
2901
|
-
case DEST_VIEW.fitR:
|
|
2902
|
-
if (view.params.length < 4) return {
|
|
2903
|
-
kind: "fit",
|
|
2904
|
-
pageObjectNumber
|
|
2905
|
-
};
|
|
2906
|
-
return {
|
|
2907
|
-
kind: "fitR",
|
|
2908
|
-
pageObjectNumber,
|
|
2909
|
-
left: view.params[0],
|
|
2910
|
-
bottom: view.params[1],
|
|
2911
|
-
right: view.params[2],
|
|
2912
|
-
top: view.params[3]
|
|
2913
|
-
};
|
|
2914
|
-
case DEST_VIEW.fitB: return {
|
|
2915
|
-
kind: "fitB",
|
|
2916
|
-
pageObjectNumber
|
|
2917
|
-
};
|
|
2918
|
-
case DEST_VIEW.fitBH: return {
|
|
2919
|
-
kind: "fitBH",
|
|
2920
|
-
pageObjectNumber,
|
|
2921
|
-
top: at(0)
|
|
2922
|
-
};
|
|
2923
|
-
case DEST_VIEW.fitBV: return {
|
|
2924
|
-
kind: "fitBV",
|
|
2925
|
-
pageObjectNumber,
|
|
2926
|
-
left: at(0)
|
|
2927
|
-
};
|
|
2928
|
-
default: return null;
|
|
2929
|
-
}
|
|
2930
|
-
}
|
|
2931
|
-
/** `/XYZ` null-aware axes via `FPDFDest_GetLocationInPage` (FPDF_BOOL is 4 bytes). */
|
|
2932
|
-
function readXyzLocation(fn, mem, destPtr) {
|
|
2933
|
-
return withScratchN(mem, [
|
|
2934
|
-
4,
|
|
2935
|
-
4,
|
|
2936
|
-
4,
|
|
2937
|
-
4,
|
|
2938
|
-
4,
|
|
2939
|
-
4
|
|
2940
|
-
], ([hasLeft, hasTop, hasZoom, left, top, zoom]) => {
|
|
2941
|
-
if (!fn.FPDFDest_GetLocationInPage(destPtr, hasLeft, hasTop, hasZoom, left, top, zoom)) return {
|
|
2942
|
-
left: null,
|
|
2943
|
-
top: null,
|
|
2944
|
-
zoom: null
|
|
2945
|
-
};
|
|
2946
|
-
return {
|
|
2947
|
-
left: readI32(mem, hasLeft) ? readF32(mem, left) : null,
|
|
2948
|
-
top: readI32(mem, hasTop) ? readF32(mem, top) : null,
|
|
2949
|
-
zoom: readI32(mem, hasZoom) ? readF32(mem, zoom) : null
|
|
2950
|
-
};
|
|
2951
|
-
});
|
|
2952
|
-
}
|
|
2953
|
-
//#endregion
|
|
2954
3235
|
//#region src/features/annotations/internal/read/readLinkAnnotation.ts
|
|
2955
3236
|
/**
|
|
2956
3237
|
* Link reader: rect/flags/relationship ride the base (a link grouped to an
|
|
2957
3238
|
* annotation is plain `inReplyTo` + `replyType: 'group'`); this module only
|
|
2958
3239
|
* materialises the normalized target.
|
|
2959
3240
|
*
|
|
2960
|
-
* ONE truth,
|
|
2961
|
-
*
|
|
2962
|
-
*
|
|
2963
|
-
*
|
|
2964
|
-
* and Named-blind) is deliberately not consulted; `FPDFLink_GetDest`
|
|
2965
|
-
* remains only for the data-only direct `/Dest`, which is not an action.
|
|
3241
|
+
* ONE truth, one projection: the target is a pure function of the SAME
|
|
3242
|
+
* payload-carrying action tree the scripting plane reads
|
|
3243
|
+
* (`base.actions.activate`) — no second native read exists any more, so the
|
|
3244
|
+
* two action-shaped surfaces cannot drift by construction.
|
|
2966
3245
|
*
|
|
2967
|
-
* `/A`
|
|
2968
|
-
*
|
|
2969
|
-
*
|
|
3246
|
+
* `/A` precedence, pinned: an activate action that exists but cannot be
|
|
3247
|
+
* executed (an `incomplete` tree, a degraded/unreadable root) projects
|
|
3248
|
+
* `unsupported` — a broken action is a dead link, never an invitation to
|
|
3249
|
+
* guess. The direct `/Dest` (which is data, not an action) is consulted
|
|
3250
|
+
* ONLY when no `/A` exists at all.
|
|
2970
3251
|
*/
|
|
2971
3252
|
function readLink(fn, mem, annotPtr, base, _rawSubtypeCode, ctx) {
|
|
2972
3253
|
return {
|
|
2973
3254
|
...base,
|
|
2974
3255
|
subtype: "link",
|
|
2975
|
-
target: readLinkTarget(fn, mem, annotPtr, ctx)
|
|
3256
|
+
target: readLinkTarget(fn, mem, annotPtr, base, ctx)
|
|
2976
3257
|
};
|
|
2977
3258
|
}
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
3259
|
+
/**
|
|
3260
|
+
* Project the navigation view from a payload-carrying activate tree. Pure —
|
|
3261
|
+
* shared with any consumer that wants the root-level navigation reading of a
|
|
3262
|
+
* tree (the link plugin's no-actions-plugin fallback uses the same law).
|
|
3263
|
+
*/
|
|
3264
|
+
function linkTargetFromActionTree(tree) {
|
|
3265
|
+
if (tree.incomplete) return { kind: "unsupported" };
|
|
3266
|
+
const root = tree.root;
|
|
3267
|
+
if (!root) return { kind: "unsupported" };
|
|
3268
|
+
switch (root.type) {
|
|
3269
|
+
case "goto": return {
|
|
3270
|
+
kind: "goto",
|
|
3271
|
+
destination: root.destination
|
|
3272
|
+
};
|
|
3273
|
+
case "uri": return {
|
|
3274
|
+
kind: "uri",
|
|
3275
|
+
uri: root.uri
|
|
3276
|
+
};
|
|
3277
|
+
case "goto-remote": return {
|
|
3278
|
+
kind: "goto-remote",
|
|
3279
|
+
file: root.filePath
|
|
3280
|
+
};
|
|
3281
|
+
case "launch": return {
|
|
3282
|
+
kind: "launch",
|
|
3283
|
+
path: root.filePath
|
|
3284
|
+
};
|
|
3285
|
+
case "javascript": return { kind: "javascript" };
|
|
3286
|
+
case "named": return {
|
|
3287
|
+
kind: "named",
|
|
3288
|
+
name: root.name
|
|
3289
|
+
};
|
|
3290
|
+
default: return { kind: "unsupported" };
|
|
2985
3291
|
}
|
|
3292
|
+
}
|
|
3293
|
+
function readLinkTarget(fn, mem, annotPtr, base, ctx) {
|
|
3294
|
+
const activate = base.actions?.activate;
|
|
3295
|
+
if (activate) return linkTargetFromActionTree(activate);
|
|
2986
3296
|
const linkPtr = fn.FPDFAnnot_GetLink(annotPtr);
|
|
2987
3297
|
if (!linkPtr) return null;
|
|
2988
3298
|
const destPtr = fn.FPDFLink_GetDest(ctx.docPtr, linkPtr);
|
|
@@ -2993,43 +3303,6 @@ function readLinkTarget(fn, mem, annotPtr, ctx) {
|
|
|
2993
3303
|
destination
|
|
2994
3304
|
} : { kind: "unsupported" };
|
|
2995
3305
|
}
|
|
2996
|
-
/** Classify the root action node and fetch its payload — the projection. */
|
|
2997
|
-
function readRootTarget(fn, mem, modelPtr, node, ctx) {
|
|
2998
|
-
switch (actionTypeFromCode(fn.EPDFAction_GetNodeType(modelPtr, node))) {
|
|
2999
|
-
case "goto": {
|
|
3000
|
-
const destPtr = fn.EPDFAction_GetNodeDest(ctx.docPtr, modelPtr, node);
|
|
3001
|
-
const destination = destPtr ? readDestination(fn, mem, ctx.docPtr, destPtr) : null;
|
|
3002
|
-
return destination ? {
|
|
3003
|
-
kind: "goto",
|
|
3004
|
-
destination
|
|
3005
|
-
} : { kind: "unsupported" };
|
|
3006
|
-
}
|
|
3007
|
-
case "uri": {
|
|
3008
|
-
const uri = readUtf8String(mem, (buf, capacity) => fn.EPDFAction_GetNodeURI(ctx.docPtr, modelPtr, node, buf, capacity));
|
|
3009
|
-
return uri == null ? { kind: "unsupported" } : {
|
|
3010
|
-
kind: "uri",
|
|
3011
|
-
uri
|
|
3012
|
-
};
|
|
3013
|
-
}
|
|
3014
|
-
case "goto-remote": return {
|
|
3015
|
-
kind: "goto-remote",
|
|
3016
|
-
file: readUtf8String(mem, (buf, capacity) => fn.EPDFAction_GetNodeFilePath(modelPtr, node, buf, capacity)) ?? ""
|
|
3017
|
-
};
|
|
3018
|
-
case "launch": return {
|
|
3019
|
-
kind: "launch",
|
|
3020
|
-
path: readUtf8String(mem, (buf, capacity) => fn.EPDFAction_GetNodeFilePath(modelPtr, node, buf, capacity)) ?? ""
|
|
3021
|
-
};
|
|
3022
|
-
case "javascript": return { kind: "javascript" };
|
|
3023
|
-
case "named": {
|
|
3024
|
-
const name = readUtf8String(mem, (buf, capacity) => fn.EPDFAction_GetNodeName(modelPtr, node, buf, capacity));
|
|
3025
|
-
return name == null ? { kind: "unsupported" } : {
|
|
3026
|
-
kind: "named",
|
|
3027
|
-
name
|
|
3028
|
-
};
|
|
3029
|
-
}
|
|
3030
|
-
default: return { kind: "unsupported" };
|
|
3031
|
-
}
|
|
3032
|
-
}
|
|
3033
3306
|
//#endregion
|
|
3034
3307
|
//#region src/features/annotations/internal/read/readRedactAnnotation.ts
|
|
3035
3308
|
/** Default `/C` marking outline (red) — the redaction marking convention and
|
|
@@ -3110,45 +3383,10 @@ function readSquare(fn, mem, annotPtr, base) {
|
|
|
3110
3383
|
};
|
|
3111
3384
|
}
|
|
3112
3385
|
//#endregion
|
|
3113
|
-
//#region src/features/annotations/internal/stampName.ts
|
|
3114
|
-
/**
|
|
3115
|
-
* Stamp `/Name` label ↔ `FPDF_ANNOT_NAME` enum code mapping for the
|
|
3116
|
-
* `EPDFAnnot_SetName` / `EPDFAnnot_GetName` fork helpers. Labels are the
|
|
3117
|
-
* PDF spec / Adobe literal name values (ISO 32000 §12.5.6.12 table 181
|
|
3118
|
-
* plus the Adobe SB/SH extended set the fork supports). Codes mirror the
|
|
3119
|
-
* `FPDF_ANNOT_NAME` enum in `public/fpdf_annot.h` — same pattern as
|
|
3120
|
-
* `lineEnding.ts` keeping engine-core PDFium-free.
|
|
3121
|
-
*/
|
|
3122
|
-
const STAMP_NAME_TO_CODE = Object.freeze({
|
|
3123
|
-
Approved: 13,
|
|
3124
|
-
Experimental: 14,
|
|
3125
|
-
NotApproved: 15,
|
|
3126
|
-
AsIs: 16,
|
|
3127
|
-
Expired: 17,
|
|
3128
|
-
NotForPublicRelease: 18,
|
|
3129
|
-
Confidential: 19,
|
|
3130
|
-
Final: 20,
|
|
3131
|
-
Sold: 21,
|
|
3132
|
-
Departmental: 22,
|
|
3133
|
-
ForComment: 23,
|
|
3134
|
-
TopSecret: 24,
|
|
3135
|
-
Draft: 25,
|
|
3136
|
-
ForPublicRelease: 26,
|
|
3137
|
-
Completed: 27,
|
|
3138
|
-
Void: 28,
|
|
3139
|
-
PreliminaryResults: 29,
|
|
3140
|
-
InformationOnly: 30,
|
|
3141
|
-
Rejected: 31,
|
|
3142
|
-
Witness: 32,
|
|
3143
|
-
InitialHere: 33,
|
|
3144
|
-
SignHere: 34,
|
|
3145
|
-
Accepted: 35
|
|
3146
|
-
});
|
|
3147
|
-
const STAMP_CODE_TO_NAME = Object.freeze(Object.fromEntries(Object.entries(STAMP_NAME_TO_CODE).map(([name, code]) => [code, name])));
|
|
3148
|
-
//#endregion
|
|
3149
3386
|
//#region src/features/annotations/internal/read/readStampAnnotation.ts
|
|
3150
3387
|
/**
|
|
3151
|
-
* Stamp DTO: base + `/Name`
|
|
3388
|
+
* Stamp DTO: base + `/Name` (standard or custom identifier, verbatim) +
|
|
3389
|
+
* transform metadata. The visual content
|
|
3152
3390
|
* stays in the `/AP` stream — rendered via `renderAppearanceImages()`,
|
|
3153
3391
|
* never surfaced as DTO data.
|
|
3154
3392
|
*/
|
|
@@ -3158,16 +3396,11 @@ function readStamp(fn, mem, annotPtr, base) {
|
|
|
3158
3396
|
return {
|
|
3159
3397
|
...base,
|
|
3160
3398
|
subtype: "stamp",
|
|
3161
|
-
name:
|
|
3399
|
+
name: readAnnotName(fn, mem, annotPtr),
|
|
3162
3400
|
...rotation != null ? { rotation } : {},
|
|
3163
3401
|
...unrotatedRect != null ? { unrotatedRect } : {}
|
|
3164
3402
|
};
|
|
3165
3403
|
}
|
|
3166
|
-
function readStampName(fn, mem, annotPtr) {
|
|
3167
|
-
const known = STAMP_CODE_TO_NAME[fn.EPDFAnnot_GetName(annotPtr)];
|
|
3168
|
-
if (known !== void 0) return known;
|
|
3169
|
-
return readAnnotString(fn, mem, annotPtr, "Name");
|
|
3170
|
-
}
|
|
3171
3404
|
//#endregion
|
|
3172
3405
|
//#region src/features/annotations/internal/annotationState.ts
|
|
3173
3406
|
/**
|
|
@@ -3223,7 +3456,7 @@ function readText(fn, mem, annotPtr, base) {
|
|
|
3223
3456
|
const color = readAnnotColor(fn, mem, annotPtr) ?? { ...DEFAULT_NOTE_COLOR$1 };
|
|
3224
3457
|
const ca = readAnnotOpacity(fn, mem, annotPtr);
|
|
3225
3458
|
const opacity = ca == null ? 1 : Math.max(0, Math.min(1, ca));
|
|
3226
|
-
const icon =
|
|
3459
|
+
const icon = NOTE_NAME_TO_ICON[readAnnotName(fn, mem, annotPtr) ?? ""] ?? DEFAULT_NOTE_ICON;
|
|
3227
3460
|
const stateRaw = readAnnotString(fn, mem, annotPtr, "State");
|
|
3228
3461
|
const stateModelRaw = readAnnotString(fn, mem, annotPtr, "StateModel");
|
|
3229
3462
|
return {
|
|
@@ -3539,7 +3772,7 @@ function readOptions(runtime, model, fieldIndex) {
|
|
|
3539
3772
|
return options;
|
|
3540
3773
|
}
|
|
3541
3774
|
/** Read one field of the native model into its per-family DTO. */
|
|
3542
|
-
function readFieldAt(runtime, model, fieldIndex, actionBudget = new ActionReadBudgetTracker()) {
|
|
3775
|
+
function readFieldAt(runtime, model, fieldIndex, docPtr, actionBudget = new ActionReadBudgetTracker()) {
|
|
3543
3776
|
const { fn } = runtime;
|
|
3544
3777
|
const fieldObjectNumber = fn.EPDFForm_GetFieldObjNum(model, fieldIndex);
|
|
3545
3778
|
const name = readWide(runtime, (buf, cap) => fn.EPDFForm_GetFieldName(model, fieldIndex, buf, cap));
|
|
@@ -3547,7 +3780,7 @@ function readFieldAt(runtime, model, fieldIndex, actionBudget = new ActionReadBu
|
|
|
3547
3780
|
const family = FAMILY_BY_CODE[fn.EPDFForm_GetFieldFamily(model, fieldIndex)] ?? "unknown";
|
|
3548
3781
|
const valueEntry = readValueEntry(runtime, model, fieldIndex, false);
|
|
3549
3782
|
const defaultValueEntry = readValueEntry(runtime, model, fieldIndex, true);
|
|
3550
|
-
const actions = readFieldActions(runtime, model, fieldIndex, actionBudget);
|
|
3783
|
+
const actions = readFieldActions(runtime, model, fieldIndex, docPtr, actionBudget);
|
|
3551
3784
|
const base = {
|
|
3552
3785
|
ref: fieldObjectNumber > 0 ? {
|
|
3553
3786
|
kind: "objectNumber",
|
|
@@ -3646,12 +3879,12 @@ function readFieldAt(runtime, model, fieldIndex, actionBudget = new ActionReadBu
|
|
|
3646
3879
|
}
|
|
3647
3880
|
}
|
|
3648
3881
|
/** Read the whole native model into a detached {@link FormSnapshot}. */
|
|
3649
|
-
function readFormSnapshot(runtime, model) {
|
|
3882
|
+
function readFormSnapshot(runtime, model, docPtr) {
|
|
3650
3883
|
const { fn } = runtime;
|
|
3651
3884
|
const count = fn.EPDFForm_CountFields(model);
|
|
3652
3885
|
const fields = [];
|
|
3653
3886
|
const actionBudget = new ActionReadBudgetTracker();
|
|
3654
|
-
for (let i = 0; i < count; i++) fields.push(readFieldAt(runtime, model, i, actionBudget));
|
|
3887
|
+
for (let i = 0; i < count; i++) fields.push(readFieldAt(runtime, model, i, docPtr, actionBudget));
|
|
3655
3888
|
const calculationOrder = [];
|
|
3656
3889
|
const calculationCount = fn.EPDFForm_CountCalculationOrder(model);
|
|
3657
3890
|
for (let index = 0; index < calculationCount; index++) {
|
|
@@ -3687,7 +3920,7 @@ function entryScalar(entry) {
|
|
|
3687
3920
|
if (entry.kind === "array") return entry.values[0] ?? "";
|
|
3688
3921
|
return "";
|
|
3689
3922
|
}
|
|
3690
|
-
function readFieldActions(runtime, model, fieldIndex, budget) {
|
|
3923
|
+
function readFieldActions(runtime, model, fieldIndex, docPtr, budget) {
|
|
3691
3924
|
const { fn, mem } = runtime;
|
|
3692
3925
|
const entries = [
|
|
3693
3926
|
["keystroke", 0],
|
|
@@ -3697,7 +3930,7 @@ function readFieldActions(runtime, model, fieldIndex, budget) {
|
|
|
3697
3930
|
];
|
|
3698
3931
|
const actions = {};
|
|
3699
3932
|
for (const [key, event] of entries) {
|
|
3700
|
-
const action = readActionModel(fn, mem, fn.EPDFForm_GetFieldActionModel(model, fieldIndex, event), budget);
|
|
3933
|
+
const action = readActionModel(fn, mem, docPtr, fn.EPDFForm_GetFieldActionModel(model, fieldIndex, event), budget);
|
|
3701
3934
|
if (action) actions[key] = action;
|
|
3702
3935
|
}
|
|
3703
3936
|
return Object.keys(actions).length > 0 ? actions : void 0;
|
|
@@ -3943,7 +4176,7 @@ function blendModeFromCode(code) {
|
|
|
3943
4176
|
* per-subtype reader builds its DTO by extending this with its own
|
|
3944
4177
|
* fields and `subtype: '...'` discriminator.
|
|
3945
4178
|
*/
|
|
3946
|
-
function readAnnotationBase(fn, mem, annotPtr, pageObjectNumber, index, revision, actionBudget = new ActionReadBudgetTracker()) {
|
|
4179
|
+
function readAnnotationBase(fn, mem, docPtr, annotPtr, pageObjectNumber, index, revision, actionBudget = new ActionReadBudgetTracker()) {
|
|
3947
4180
|
const identity = readAnnotationIdentity(fn, mem, annotPtr, pageObjectNumber, index, revision);
|
|
3948
4181
|
const rect = readAnnotRect(fn, mem, annotPtr);
|
|
3949
4182
|
const flags = readAnnotFlags(fn, annotPtr);
|
|
@@ -3955,7 +4188,7 @@ function readAnnotationBase(fn, mem, annotPtr, pageObjectNumber, index, revision
|
|
|
3955
4188
|
const blendMode = blendModeFromCode(fn.EPDFAnnot_GetBlendMode(annotPtr));
|
|
3956
4189
|
const embd = readEmbedMetadata(fn, mem, annotPtr);
|
|
3957
4190
|
const relationship = readAnnotationRelationship(fn, mem, annotPtr, pageObjectNumber);
|
|
3958
|
-
const actions = readAnnotationActions(fn, mem, annotPtr, actionBudget);
|
|
4191
|
+
const actions = readAnnotationActions(fn, mem, docPtr, annotPtr, actionBudget);
|
|
3959
4192
|
return {
|
|
3960
4193
|
ref: identity.ref,
|
|
3961
4194
|
pageObjectNumber,
|
|
@@ -3979,7 +4212,7 @@ function readAnnotationBase(fn, mem, annotPtr, pageObjectNumber, index, revision
|
|
|
3979
4212
|
...actions ? { actions } : {}
|
|
3980
4213
|
};
|
|
3981
4214
|
}
|
|
3982
|
-
function readAnnotationActions(fn, mem, annotPtr, budget) {
|
|
4215
|
+
function readAnnotationActions(fn, mem, docPtr, annotPtr, budget) {
|
|
3983
4216
|
const events = [
|
|
3984
4217
|
["activate", 0],
|
|
3985
4218
|
["cursorEnter", 1],
|
|
@@ -3995,7 +4228,7 @@ function readAnnotationActions(fn, mem, annotPtr, budget) {
|
|
|
3995
4228
|
];
|
|
3996
4229
|
const actions = {};
|
|
3997
4230
|
for (const [key, event] of events) {
|
|
3998
|
-
const action = readActionModel(fn, mem, fn.EPDFAnnot_GetActionModel(annotPtr, event), budget);
|
|
4231
|
+
const action = readActionModel(fn, mem, docPtr, fn.EPDFAnnot_GetActionModel(annotPtr, event), budget);
|
|
3999
4232
|
if (action) actions[key] = action;
|
|
4000
4233
|
}
|
|
4001
4234
|
return Object.keys(actions).length > 0 ? actions : void 0;
|
|
@@ -4026,7 +4259,7 @@ function collectPageAnnotations(input) {
|
|
|
4026
4259
|
const annotPtr = getAnnotPtrAt(i);
|
|
4027
4260
|
if (!annotPtr) continue;
|
|
4028
4261
|
try {
|
|
4029
|
-
const base = readAnnotationBase(fn, mem, annotPtr, pageObjectNumber, i, revision, actionBudget);
|
|
4262
|
+
const base = readAnnotationBase(fn, mem, readCtx.docPtr, annotPtr, pageObjectNumber, i, revision, actionBudget);
|
|
4030
4263
|
const subtypeCode = fn.FPDFAnnot_GetSubtype(annotPtr);
|
|
4031
4264
|
const { reader } = pickReader(subtypeCode);
|
|
4032
4265
|
const dto = reader(fn, mem, annotPtr, base, subtypeCode, readCtx);
|
|
@@ -4964,7 +5197,7 @@ function computeMutationImpact(inputs) {
|
|
|
4964
5197
|
* `AnnotationUpdateResult.updated`.
|
|
4965
5198
|
*/
|
|
4966
5199
|
function readAnnotationFromPtr(fn, mem, annotPtr, pageObjectNumber, index, revision, ctx) {
|
|
4967
|
-
const base = readAnnotationBase(fn, mem, annotPtr, pageObjectNumber, index, revision);
|
|
5200
|
+
const base = readAnnotationBase(fn, mem, ctx.docPtr, annotPtr, pageObjectNumber, index, revision);
|
|
4968
5201
|
const subtypeCode = fn.FPDFAnnot_GetSubtype(annotPtr);
|
|
4969
5202
|
const { reader } = pickReader(subtypeCode);
|
|
4970
5203
|
return reader(fn, mem, annotPtr, base, subtypeCode, ctx);
|
|
@@ -5245,7 +5478,7 @@ function isFileAttachmentSubtype(subtype) {
|
|
|
5245
5478
|
return subtype === "file-attachment";
|
|
5246
5479
|
}
|
|
5247
5480
|
function setFileAttachmentIcon(fn, annotPtr, icon) {
|
|
5248
|
-
if (!fn.EPDFAnnot_SetName(annotPtr,
|
|
5481
|
+
if (!fn.EPDFAnnot_SetName(annotPtr, FILE_ICON_TO_NAME[icon])) throw new EngineError(EngineErrorCode.Unknown, "EPDFAnnot_SetName returned false");
|
|
5249
5482
|
}
|
|
5250
5483
|
function requireFileResource(file, ctx) {
|
|
5251
5484
|
const resource = ctx?.resources?.[file.resource];
|
|
@@ -5907,12 +6140,12 @@ const STAMP_FIT_TO_CODE = {
|
|
|
5907
6140
|
* creating an annotation or strengthening a weak annotation id.
|
|
5908
6141
|
*/
|
|
5909
6142
|
function preflightStampDraft(draft, ctx) {
|
|
5910
|
-
if (draft.name !== void 0)
|
|
6143
|
+
if (draft.name !== void 0) requireStampName(draft.name);
|
|
5911
6144
|
requireStampFit(draft.fit ?? "contain");
|
|
5912
6145
|
requireStampContent(draft.source, ctx);
|
|
5913
6146
|
}
|
|
5914
6147
|
function preflightStampPatch(patch, ctx) {
|
|
5915
|
-
if (patch.name !== void 0)
|
|
6148
|
+
if (patch.name !== void 0 && patch.name !== null) requireStampName(patch.name);
|
|
5916
6149
|
requireStampFit(patch.fit ?? "contain");
|
|
5917
6150
|
if (patch.source !== void 0) requireStampContent(patch.source, ctx);
|
|
5918
6151
|
}
|
|
@@ -5938,7 +6171,8 @@ function applyStampDraft(fn, mem, annotPtr, draft, ctx) {
|
|
|
5938
6171
|
}
|
|
5939
6172
|
function applyStampPatch(fn, mem, annotPtr, patch, ctx) {
|
|
5940
6173
|
applyAnnotationBasePatch(fn, mem, annotPtr, patch);
|
|
5941
|
-
if (patch.name
|
|
6174
|
+
if (patch.name === null) fn.EPDFAnnot_RemoveKey(annotPtr, "Name");
|
|
6175
|
+
else if (patch.name !== void 0) setStampName(fn, annotPtr, patch.name);
|
|
5942
6176
|
if (patch.source !== void 0) {
|
|
5943
6177
|
const rect = patch.rect ?? readAnnotRect(fn, mem, annotPtr);
|
|
5944
6178
|
authorStampAppearance(fn, mem, annotPtr, patch.source, patch.fit ?? "contain", {
|
|
@@ -5958,15 +6192,14 @@ function applyStampPatch(fn, mem, annotPtr, patch, ctx) {
|
|
|
5958
6192
|
function isStampSubtype(subtype) {
|
|
5959
6193
|
return subtype === "stamp";
|
|
5960
6194
|
}
|
|
6195
|
+
/** Any non-empty name: standard ('Approved') or custom ('#LBGiYhk8V…') —
|
|
6196
|
+
* the fork writes a name object and escapes it; predefined sets are a
|
|
6197
|
+
* reader concern (ISO 32000-2 table 187 allows additional names). */
|
|
5961
6198
|
function setStampName(fn, annotPtr, name) {
|
|
5962
|
-
|
|
5963
|
-
if (code === void 0) throw new EngineError(EngineErrorCode.Unknown, "stamp name preflight invariant broken");
|
|
5964
|
-
if (!fn.EPDFAnnot_SetName(annotPtr, code)) throw new EngineError(EngineErrorCode.Unknown, "EPDFAnnot_SetName returned false");
|
|
6199
|
+
if (!fn.EPDFAnnot_SetName(annotPtr, name)) throw new EngineError(EngineErrorCode.Unknown, "EPDFAnnot_SetName returned false");
|
|
5965
6200
|
}
|
|
5966
|
-
function
|
|
5967
|
-
|
|
5968
|
-
if (code === void 0) throw new EngineError(EngineErrorCode.InvalidArg, `unknown stamp name '${name}'; supported names: ${Object.keys(STAMP_NAME_TO_CODE).join(", ")}`);
|
|
5969
|
-
return code;
|
|
6201
|
+
function requireStampName(name) {
|
|
6202
|
+
if (name.length === 0) throw new EngineError(EngineErrorCode.InvalidArg, "stamp name must be non-empty");
|
|
5970
6203
|
}
|
|
5971
6204
|
function requireStampFit(fit) {
|
|
5972
6205
|
if (STAMP_FIT_TO_CODE[fit] === void 0) throw new EngineError(EngineErrorCode.InvalidArg, `unknown stamp fit '${String(fit)}'; expected contain, cover, or fill`);
|
|
@@ -6154,7 +6387,7 @@ function isTextSubtype(subtype) {
|
|
|
6154
6387
|
return subtype === "text";
|
|
6155
6388
|
}
|
|
6156
6389
|
function setNoteIcon(fn, annotPtr, icon) {
|
|
6157
|
-
if (!fn.EPDFAnnot_SetName(annotPtr,
|
|
6390
|
+
if (!fn.EPDFAnnot_SetName(annotPtr, NOTE_ICON_TO_NAME[icon])) throw new EngineError(EngineErrorCode.Unknown, "EPDFAnnot_SetName returned false");
|
|
6158
6391
|
}
|
|
6159
6392
|
//#endregion
|
|
6160
6393
|
//#region src/features/annotations/internal/write/writeVertexAnnotation.ts
|
|
@@ -6881,6 +7114,141 @@ var AnnotationMutator = class {
|
|
|
6881
7114
|
}
|
|
6882
7115
|
};
|
|
6883
7116
|
//#endregion
|
|
7117
|
+
//#region src/features/annotations/AnnotationFlattener.ts
|
|
7118
|
+
const FLATTEN_FAIL$1 = 0;
|
|
7119
|
+
const FLATTEN_SUCCESS$1 = 1;
|
|
7120
|
+
const FLATTEN_NOTHING_TO_DO$1 = 2;
|
|
7121
|
+
const STATUS_APPLIED = 0;
|
|
7122
|
+
const STATUS_NOT_ON_PAGE = 2;
|
|
7123
|
+
const FPDF_NO_INCREMENTAL$1 = 2;
|
|
7124
|
+
/**
|
|
7125
|
+
* The annotation-plane flatten verbs — `pages.flatten` for a chosen set:
|
|
7126
|
+
* in place (`flatten`) or into a new single-page document
|
|
7127
|
+
* (`exportAppearance`). Both resolve refs to native handles on the page,
|
|
7128
|
+
* hand the SET to the fork (one candidate plan, one placement writer — the
|
|
7129
|
+
* same code whole-page flatten runs), and release every handle afterwards.
|
|
7130
|
+
*/
|
|
7131
|
+
var AnnotationFlattener = class {
|
|
7132
|
+
constructor(runtime, session) {
|
|
7133
|
+
this.runtime = runtime;
|
|
7134
|
+
this.session = session;
|
|
7135
|
+
}
|
|
7136
|
+
flatten(pageObjectNumber, refs, usage, signal) {
|
|
7137
|
+
throwIfAborted(signal);
|
|
7138
|
+
this.requireRefs("annotations.flatten", pageObjectNumber, refs);
|
|
7139
|
+
const { fn, mem } = this.runtime;
|
|
7140
|
+
const pool = this.session.pagePool();
|
|
7141
|
+
const pagePtr = pool.acquire(pageObjectNumber);
|
|
7142
|
+
try {
|
|
7143
|
+
const annotPtrs = this.resolveAll(pagePtr, refs);
|
|
7144
|
+
let code;
|
|
7145
|
+
let statuses;
|
|
7146
|
+
try {
|
|
7147
|
+
[code, statuses] = this.withHandleArray(annotPtrs, (arrayPtr) => withScratch(mem, 4 * refs.length, (statusPtr) => {
|
|
7148
|
+
const rc = fn.EPDFPage_FlattenAnnotations(pagePtr, arrayPtr, refs.length, usage === "print" ? 1 : 0, statusPtr);
|
|
7149
|
+
const out = [];
|
|
7150
|
+
for (let i = 0; i < refs.length; i++) out.push(Number(mem.peek(statusPtr, "i32", 4 * i)));
|
|
7151
|
+
return [rc, out];
|
|
7152
|
+
}));
|
|
7153
|
+
} finally {
|
|
7154
|
+
for (const annotPtr of annotPtrs) fn.FPDFPage_CloseAnnot(annotPtr);
|
|
7155
|
+
}
|
|
7156
|
+
if (code === FLATTEN_FAIL$1) {
|
|
7157
|
+
const foreign = statuses.findIndex((status) => status === STATUS_NOT_ON_PAGE);
|
|
7158
|
+
throw new EngineError(foreign >= 0 ? EngineErrorCode.InvalidArg : EngineErrorCode.Unknown, foreign >= 0 ? `annotations.flatten: ref ${foreign} is not an annotation of page ${pageObjectNumber}` : "native annotation flatten failed after preflight");
|
|
7159
|
+
}
|
|
7160
|
+
const results = refs.map((ref, i) => ({
|
|
7161
|
+
ref,
|
|
7162
|
+
status: statuses[i] === STATUS_APPLIED ? "applied" : "skipped"
|
|
7163
|
+
}));
|
|
7164
|
+
if (code === FLATTEN_NOTHING_TO_DO$1 || code !== FLATTEN_SUCCESS$1) return {
|
|
7165
|
+
pageObjectNumber,
|
|
7166
|
+
usage,
|
|
7167
|
+
results,
|
|
7168
|
+
meta: null
|
|
7169
|
+
};
|
|
7170
|
+
this.session.noteMutation();
|
|
7171
|
+
this.session.bumpRevision(pageObjectNumber);
|
|
7172
|
+
try {
|
|
7173
|
+
new AnnotationReader(this.runtime, this.session).list(pageObjectNumber, signal);
|
|
7174
|
+
} catch {}
|
|
7175
|
+
return {
|
|
7176
|
+
pageObjectNumber,
|
|
7177
|
+
usage,
|
|
7178
|
+
results,
|
|
7179
|
+
meta: {
|
|
7180
|
+
affectedPages: [this.session.pageState(pageObjectNumber)],
|
|
7181
|
+
cacheDelta: null
|
|
7182
|
+
}
|
|
7183
|
+
};
|
|
7184
|
+
} finally {
|
|
7185
|
+
pool.release(pageObjectNumber);
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
7188
|
+
exportAppearance(pageObjectNumber, refs, signal) {
|
|
7189
|
+
throwIfAborted(signal);
|
|
7190
|
+
this.requireRefs("annotations.exportAppearance", pageObjectNumber, refs);
|
|
7191
|
+
const { fn, mem } = this.runtime;
|
|
7192
|
+
const pool = this.session.pagePool();
|
|
7193
|
+
const pagePtr = pool.acquire(pageObjectNumber);
|
|
7194
|
+
let exportedPtr = null;
|
|
7195
|
+
let pdfPtr = null;
|
|
7196
|
+
try {
|
|
7197
|
+
const annotPtrs = this.resolveAll(pagePtr, refs);
|
|
7198
|
+
try {
|
|
7199
|
+
exportedPtr = this.withHandleArray(annotPtrs, (arrayPtr) => fn.EPDFPage_ExportAnnotationsAsDocument(pagePtr, arrayPtr, refs.length));
|
|
7200
|
+
} finally {
|
|
7201
|
+
for (const annotPtr of annotPtrs) fn.FPDFPage_CloseAnnot(annotPtr);
|
|
7202
|
+
}
|
|
7203
|
+
if (!exportedPtr) throw new EngineError(EngineErrorCode.InvalidArg, "annotations.exportAppearance: every ref must be a visible annotation of this page with a normal appearance");
|
|
7204
|
+
return withScratch(mem, 4, (sizePtr) => {
|
|
7205
|
+
mem.poke(sizePtr, "i32", 0);
|
|
7206
|
+
pdfPtr = fn.EPDF_SaveDocumentToOwnedBuffer(exportedPtr, FPDF_NO_INCREMENTAL$1, sizePtr);
|
|
7207
|
+
const size = Number(mem.peek(sizePtr, "i32"));
|
|
7208
|
+
if (!pdfPtr || size <= 0) throw new EngineError(EngineErrorCode.DocOpenFailed, "failed to save exported appearances");
|
|
7209
|
+
const bytes = mem.readBytes(pdfPtr, size);
|
|
7210
|
+
const buffer = new ArrayBuffer(bytes.byteLength);
|
|
7211
|
+
new Uint8Array(buffer).set(bytes);
|
|
7212
|
+
return {
|
|
7213
|
+
bytes: buffer,
|
|
7214
|
+
size
|
|
7215
|
+
};
|
|
7216
|
+
});
|
|
7217
|
+
} finally {
|
|
7218
|
+
if (pdfPtr) fn.EPDF_FreeBuffer(pdfPtr);
|
|
7219
|
+
if (exportedPtr) fn.FPDF_CloseDocument(exportedPtr);
|
|
7220
|
+
pool.release(pageObjectNumber);
|
|
7221
|
+
}
|
|
7222
|
+
}
|
|
7223
|
+
/** Resolve every ref on `pagePtr` (NotFound / InvalidReference from the
|
|
7224
|
+
* resolver on caller error); on any failure, close what was opened. */
|
|
7225
|
+
resolveAll(pagePtr, refs) {
|
|
7226
|
+
const { fn } = this.runtime;
|
|
7227
|
+
const annotPtrs = [];
|
|
7228
|
+
try {
|
|
7229
|
+
for (const ref of refs) annotPtrs.push(resolveAnnotPtr(this.runtime, this.session, pagePtr, ref));
|
|
7230
|
+
return annotPtrs;
|
|
7231
|
+
} catch (error) {
|
|
7232
|
+
for (const annotPtr of annotPtrs) fn.FPDFPage_CloseAnnot(annotPtr);
|
|
7233
|
+
throw error;
|
|
7234
|
+
}
|
|
7235
|
+
}
|
|
7236
|
+
/** Marshal an `FPDF_ANNOTATION*` array for the call's duration. */
|
|
7237
|
+
withHandleArray(annotPtrs, body) {
|
|
7238
|
+
const { mem } = this.runtime;
|
|
7239
|
+
const isWasm = this.runtime.kind === "wasm";
|
|
7240
|
+
const ptrSize = isWasm ? 4 : 8;
|
|
7241
|
+
return withScratch(mem, Math.max(1, annotPtrs.length * ptrSize), (arrayPtr) => {
|
|
7242
|
+
annotPtrs.forEach((ptr, i) => isWasm ? mem.poke(arrayPtr, "i32", Number(ptr), i * 4) : mem.poke(arrayPtr, "i64", ptr, i * 8));
|
|
7243
|
+
return body(arrayPtr);
|
|
7244
|
+
});
|
|
7245
|
+
}
|
|
7246
|
+
requireRefs(op, pageObjectNumber, refs) {
|
|
7247
|
+
if (refs.length === 0) throw new EngineError(EngineErrorCode.InvalidArg, `${op} requires at least one ref`);
|
|
7248
|
+
for (const ref of refs) if (ref.pageObjectNumber !== pageObjectNumber) throw new EngineError(EngineErrorCode.InvalidArg, `${op} refs must all target page ${pageObjectNumber}; got ref on page ${ref.pageObjectNumber}`);
|
|
7249
|
+
}
|
|
7250
|
+
};
|
|
7251
|
+
//#endregion
|
|
6884
7252
|
//#region src/features/pages/PagesFlattener.ts
|
|
6885
7253
|
const FLATTEN_FAIL = 0;
|
|
6886
7254
|
const FLATTEN_SUCCESS = 1;
|
|
@@ -8182,13 +8550,13 @@ var FormReader = class {
|
|
|
8182
8550
|
snapshot(signal) {
|
|
8183
8551
|
throwIfAborted(signal);
|
|
8184
8552
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8185
|
-
return readFormSnapshot(this.runtime, model);
|
|
8553
|
+
return readFormSnapshot(this.runtime, model, this.session.requireDocPtr());
|
|
8186
8554
|
}
|
|
8187
8555
|
field(ref, signal) {
|
|
8188
8556
|
throwIfAborted(signal);
|
|
8189
8557
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8190
8558
|
const { fieldIndex } = resolveFieldRef(this.runtime, model, ref);
|
|
8191
|
-
return readFieldAt(this.runtime, model, fieldIndex);
|
|
8559
|
+
return readFieldAt(this.runtime, model, fieldIndex, this.session.requireDocPtr());
|
|
8192
8560
|
}
|
|
8193
8561
|
/**
|
|
8194
8562
|
* Serialize form data. Exports read the reconciled view (recovered
|
|
@@ -8344,7 +8712,7 @@ var FormMutator = class {
|
|
|
8344
8712
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8345
8713
|
const resolved = resolveFieldRef(this.runtime, model, ref);
|
|
8346
8714
|
this.assertWritable(resolved.fieldObjectNumber);
|
|
8347
|
-
const before = readFieldAt(this.runtime, model, resolved.fieldIndex);
|
|
8715
|
+
const before = readFieldAt(this.runtime, model, resolved.fieldIndex, this.session.requireDocPtr());
|
|
8348
8716
|
if (!FAMILY_BY_VALUE_TYPE[value.type].includes(before.family)) throw new EngineError(EngineErrorCode.InvalidArg, `value type '${value.type}' does not apply to a '${before.family}' field`);
|
|
8349
8717
|
const changed = this.applyWrite(resolved.fieldObjectNumber, value);
|
|
8350
8718
|
return this.readBack(resolved.fieldObjectNumber, changed);
|
|
@@ -8380,7 +8748,7 @@ var FormMutator = class {
|
|
|
8380
8748
|
const fresh = acquireFormModel(this.runtime, this.session);
|
|
8381
8749
|
return {
|
|
8382
8750
|
...counters,
|
|
8383
|
-
snapshot: readFormSnapshot(this.runtime, fresh),
|
|
8751
|
+
snapshot: readFormSnapshot(this.runtime, fresh, this.session.requireDocPtr()),
|
|
8384
8752
|
meta: EMPTY_META$1
|
|
8385
8753
|
};
|
|
8386
8754
|
}
|
|
@@ -8453,7 +8821,7 @@ var FormMutator = class {
|
|
|
8453
8821
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8454
8822
|
const resolved = resolveFieldRef(this.runtime, model, ref);
|
|
8455
8823
|
this.assertWritable(resolved.fieldObjectNumber);
|
|
8456
|
-
const before = readFieldAt(this.runtime, model, resolved.fieldIndex);
|
|
8824
|
+
const before = readFieldAt(this.runtime, model, resolved.fieldIndex, this.session.requireDocPtr());
|
|
8457
8825
|
if (before.family !== patch.family) throw new EngineError(EngineErrorCode.InvalidArg, `patch family '${patch.family}' does not match field family '${before.family}'`);
|
|
8458
8826
|
const fieldObjectNumber = resolved.fieldObjectNumber;
|
|
8459
8827
|
if (patch.name !== void 0) this.applyWideSetter(fn.EPDFForm_SetFieldName, fieldObjectNumber, patch.name, `cannot rename to "${patch.name}" (sibling conflict or invalid)`);
|
|
@@ -8484,7 +8852,7 @@ var FormMutator = class {
|
|
|
8484
8852
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8485
8853
|
const resolved = resolveFieldRef(this.runtime, model, ref);
|
|
8486
8854
|
this.assertWritable(resolved.fieldObjectNumber);
|
|
8487
|
-
const before = readFieldAt(this.runtime, model, resolved.fieldIndex);
|
|
8855
|
+
const before = readFieldAt(this.runtime, model, resolved.fieldIndex, this.session.requireDocPtr());
|
|
8488
8856
|
if (!withScratchN(mem, [256 * 4, 4], ([buf, countPtr]) => {
|
|
8489
8857
|
mem.poke(countPtr, "i32", 0);
|
|
8490
8858
|
return fn.EPDFForm_DeleteField(this.session.requireDocPtr(), resolved.fieldObjectNumber, buf, 256, countPtr);
|
|
@@ -8504,7 +8872,7 @@ var FormMutator = class {
|
|
|
8504
8872
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8505
8873
|
const resolved = resolveFieldRef(this.runtime, model, ref);
|
|
8506
8874
|
this.assertWritable(resolved.fieldObjectNumber);
|
|
8507
|
-
const before = readFieldAt(this.runtime, model, resolved.fieldIndex);
|
|
8875
|
+
const before = readFieldAt(this.runtime, model, resolved.fieldIndex, this.session.requireDocPtr());
|
|
8508
8876
|
const toggle = before.family === "checkbox" || before.family === "radio";
|
|
8509
8877
|
const state = toggle ? onState ?? (before.family === "checkbox" ? "Yes" : "") : "";
|
|
8510
8878
|
if (toggle && (!state || state === "Off")) throw new EngineError(EngineErrorCode.InvalidArg, "attaching to a radio group needs a non-\"Off\" onState");
|
|
@@ -8550,7 +8918,7 @@ var FormMutator = class {
|
|
|
8550
8918
|
const fresh = acquireFormModel(this.runtime, this.session);
|
|
8551
8919
|
const fieldIndex = this.runtime.fn.EPDFForm_GetFieldIndexByObjNum(fresh, fieldObjectNumber);
|
|
8552
8920
|
if (fieldIndex < 0) throw new EngineError(EngineErrorCode.Unknown, "form field vanished after write");
|
|
8553
|
-
return readFieldAt(this.runtime, fresh, fieldIndex);
|
|
8921
|
+
return readFieldAt(this.runtime, fresh, fieldIndex, this.session.requireDocPtr());
|
|
8554
8922
|
}
|
|
8555
8923
|
assertWritable(fieldObjectNumber) {
|
|
8556
8924
|
if (fieldObjectNumber === 0) throw new EngineError(EngineErrorCode.InvalidArg, "form field is stored as a direct object and cannot be written");
|
|
@@ -8596,7 +8964,7 @@ var FormMutator = class {
|
|
|
8596
8964
|
const fresh = acquireFormModel(this.runtime, this.session);
|
|
8597
8965
|
const fieldIndex = this.runtime.fn.EPDFForm_GetFieldIndexByObjNum(fresh, fieldObjectNumber);
|
|
8598
8966
|
if (fieldIndex < 0) throw new EngineError(EngineErrorCode.Unknown, "form field vanished after write");
|
|
8599
|
-
const field = readFieldAt(this.runtime, fresh, fieldIndex);
|
|
8967
|
+
const field = readFieldAt(this.runtime, fresh, fieldIndex, this.session.requireDocPtr());
|
|
8600
8968
|
const changedSet = new Set(changedObjNums);
|
|
8601
8969
|
return {
|
|
8602
8970
|
field,
|
|
@@ -8742,7 +9110,7 @@ var FormsEffectsApplier = class {
|
|
|
8742
9110
|
if (refs.length === 0) throw new EngineError(EngineErrorCode.InvalidArg, "reset effect requires at least one field");
|
|
8743
9111
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8744
9112
|
const resolved = refs.map((ref) => this.resolve(model, ref));
|
|
8745
|
-
const fields = resolved.map(({ fieldIndex }) => readFieldAt(this.runtime, model, fieldIndex, actionBudget));
|
|
9113
|
+
const fields = resolved.map(({ fieldIndex }) => readFieldAt(this.runtime, model, fieldIndex, this.session.requireDocPtr(), actionBudget));
|
|
8746
9114
|
validateEffect(effect, fields);
|
|
8747
9115
|
return {
|
|
8748
9116
|
effect,
|
|
@@ -8767,7 +9135,7 @@ var FormsEffectsApplier = class {
|
|
|
8767
9135
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8768
9136
|
const index = this.runtime.fn.EPDFForm_GetFieldIndexByObjNum(model, fieldObjectNumber);
|
|
8769
9137
|
if (index < 0) throw new EngineError(EngineErrorCode.InvalidReference, "form field disappeared");
|
|
8770
|
-
return readFieldAt(this.runtime, model, index, actionBudget);
|
|
9138
|
+
return readFieldAt(this.runtime, model, index, this.session.requireDocPtr(), actionBudget);
|
|
8771
9139
|
}
|
|
8772
9140
|
readFieldsBestEffort(fieldObjectNumbers, actionBudget) {
|
|
8773
9141
|
const fields = [];
|
|
@@ -9134,22 +9502,26 @@ var DocumentActionsReader = class {
|
|
|
9134
9502
|
} finally {
|
|
9135
9503
|
fn.FPDFDoc_CloseJavaScriptAction(namedPtr);
|
|
9136
9504
|
}
|
|
9137
|
-
|
|
9505
|
+
budget.reservePayloadBytes(name.length);
|
|
9506
|
+
const action = requireAction(readActionModel(fn, mem, docPtr, fn.EPDFDoc_GetNamedJavaScriptActionModel(docPtr, index), budget), "name-tree script", index);
|
|
9138
9507
|
nameTreeScripts.push({
|
|
9139
9508
|
name,
|
|
9140
9509
|
action
|
|
9141
9510
|
});
|
|
9142
9511
|
}
|
|
9143
|
-
const openAction = readActionModel(fn, mem, fn.EPDFDoc_GetOpenActionModel(docPtr), budget);
|
|
9512
|
+
const openAction = readActionModel(fn, mem, docPtr, fn.EPDFDoc_GetOpenActionModel(docPtr), budget);
|
|
9513
|
+
const openDestPtr = openAction ? NULL_PTR : fn.EPDFDoc_GetOpenActionDest(docPtr);
|
|
9514
|
+
const openDestination = openDestPtr !== NULL_PTR ? readDestination(fn, mem, docPtr, openDestPtr) : null;
|
|
9144
9515
|
const additional = {};
|
|
9145
9516
|
for (const [key, event] of DOCUMENT_ACTION_EVENTS) {
|
|
9146
9517
|
throwIfAborted(signal);
|
|
9147
|
-
const action = readActionModel(fn, mem, fn.EPDFDoc_GetAdditionalActionModel(docPtr, event), budget);
|
|
9518
|
+
const action = readActionModel(fn, mem, docPtr, fn.EPDFDoc_GetAdditionalActionModel(docPtr, event), budget);
|
|
9148
9519
|
if (action) additional[key] = action;
|
|
9149
9520
|
}
|
|
9150
9521
|
return {
|
|
9151
9522
|
nameTreeScripts,
|
|
9152
9523
|
openAction,
|
|
9524
|
+
openDestination,
|
|
9153
9525
|
...additional
|
|
9154
9526
|
};
|
|
9155
9527
|
}
|
|
@@ -9483,6 +9855,18 @@ var WorkerHost = class {
|
|
|
9483
9855
|
case "pages.delete":
|
|
9484
9856
|
resultPack = this.handlePagesDelete(msg, ctrl.signal);
|
|
9485
9857
|
break;
|
|
9858
|
+
case "pages.setName":
|
|
9859
|
+
resultPack = this.handlePagesSetName(msg, ctrl.signal);
|
|
9860
|
+
break;
|
|
9861
|
+
case "annotations.flatten":
|
|
9862
|
+
resultPack = this.handleAnnotationsFlatten(msg, ctrl.signal);
|
|
9863
|
+
break;
|
|
9864
|
+
case "annotations.exportAppearance":
|
|
9865
|
+
resultPack = this.handleAnnotationsExportAppearance(msg, ctrl.signal);
|
|
9866
|
+
break;
|
|
9867
|
+
case "pages.removeName":
|
|
9868
|
+
resultPack = this.handlePagesRemoveName(msg, ctrl.signal);
|
|
9869
|
+
break;
|
|
9486
9870
|
case "pages.flatten":
|
|
9487
9871
|
resultPack = this.handlePagesFlatten(msg, ctrl.signal);
|
|
9488
9872
|
break;
|
|
@@ -9710,6 +10094,27 @@ var WorkerHost = class {
|
|
|
9710
10094
|
result
|
|
9711
10095
|
}, req.artifactPath);
|
|
9712
10096
|
}
|
|
10097
|
+
handleAnnotationsFlatten(req, signal) {
|
|
10098
|
+
const session = this.requireSession(req);
|
|
10099
|
+
const result = new AnnotationFlattener(this.runtime, session).flatten(req.pageObjectNumber, req.refs, req.usage, signal);
|
|
10100
|
+
if (result.meta === null) return wirePack({
|
|
10101
|
+
tag: "annotations.flatten",
|
|
10102
|
+
result
|
|
10103
|
+
});
|
|
10104
|
+
return this.finishMutation(session, {
|
|
10105
|
+
tag: "annotations.flatten",
|
|
10106
|
+
result
|
|
10107
|
+
}, req.artifactPath);
|
|
10108
|
+
}
|
|
10109
|
+
handleAnnotationsExportAppearance(req, signal) {
|
|
10110
|
+
const session = this.requireSession(req);
|
|
10111
|
+
const exported = new AnnotationFlattener(this.runtime, session).exportAppearance(req.pageObjectNumber, req.refs, signal);
|
|
10112
|
+
return wirePack({
|
|
10113
|
+
tag: "annotations.exportAppearance",
|
|
10114
|
+
bytes: exported.bytes,
|
|
10115
|
+
size: exported.size
|
|
10116
|
+
}, [exported.bytes]);
|
|
10117
|
+
}
|
|
9713
10118
|
handleAnnotationsMove(req, signal) {
|
|
9714
10119
|
const session = this.requireSession(req);
|
|
9715
10120
|
const result = new AnnotationMutator(this.runtime, session).move(req.pageObjectNumber, req.refs, req.toIndex, signal);
|
|
@@ -9749,6 +10154,26 @@ var WorkerHost = class {
|
|
|
9749
10154
|
result
|
|
9750
10155
|
}, req.artifactPath);
|
|
9751
10156
|
}
|
|
10157
|
+
handlePagesSetName(req, signal) {
|
|
10158
|
+
const session = this.requireSession(req);
|
|
10159
|
+
const result = new PagesMutator(this.runtime, session).setName({
|
|
10160
|
+
name: req.name,
|
|
10161
|
+
pageObjectNumber: req.pageObjectNumber,
|
|
10162
|
+
...req.replace !== void 0 ? { replace: req.replace } : {}
|
|
10163
|
+
}, signal);
|
|
10164
|
+
return this.finishMutation(session, {
|
|
10165
|
+
tag: "pages.setName",
|
|
10166
|
+
result
|
|
10167
|
+
}, req.artifactPath);
|
|
10168
|
+
}
|
|
10169
|
+
handlePagesRemoveName(req, signal) {
|
|
10170
|
+
const session = this.requireSession(req);
|
|
10171
|
+
const result = new PagesMutator(this.runtime, session).removeName({ name: req.name }, signal);
|
|
10172
|
+
return this.finishMutation(session, {
|
|
10173
|
+
tag: "pages.removeName",
|
|
10174
|
+
result
|
|
10175
|
+
}, req.artifactPath);
|
|
10176
|
+
}
|
|
9752
10177
|
handlePagesFlatten(req, signal) {
|
|
9753
10178
|
const session = this.requireSession(req);
|
|
9754
10179
|
const result = new PagesFlattener(this.runtime, session).flatten(req.pageObjectNumbers, req.usage, signal);
|
|
@@ -10323,6 +10748,6 @@ function passwordRequiredProbe() {
|
|
|
10323
10748
|
};
|
|
10324
10749
|
}
|
|
10325
10750
|
//#endregion
|
|
10326
|
-
export { ALL_STANDARD_SECURITY_PERMISSIONS, ActionReadBudgetTracker, AnnotationAppearanceReader, AnnotationMutator, AnnotationReader, AttachmentMutator, AttachmentReader, BaseDocumentRegistry, CloseStack, DocumentActionsReader, PagesMutator as DocumentPagesMutator, PagesMutator, DocumentSaver, DocumentSession, EPDF_CHAR_GEOMETRY_LAYOUT, EventHub, FontRegistrar, FormMutator, FormReader, FormsEffectsApplier, LocalRevisionAuthority, MetadataMutator, MetadataReader, PageGeometryReader, PagesReader as PageLayoutReader, PagesReader, PagePtrPool, PageRenderReader as PageRasterReader, PageRenderReader, PageTextReader, PagesExtractor, PagesFlattener, PagesInserter, RawAnnotationReader, RedactionApplier, SearchReader, SecurityReader, SessionEventPublisher, WorkerHost, buildRunsFromRawGlyphs, computeMutationImpact, destroyLibrary, disposeFormModel, ensureInitialized, formatPdfDate, generateUuid, hasAllStandardSecurityPermissions, normalizeU32, openFatMemoryDocument, openLayerDocument, pdfDateToIso, readActionModel, readAttachmentFileInfo, throwIfAborted, writeAttachmentFilePayload };
|
|
10751
|
+
export { ALL_STANDARD_SECURITY_PERMISSIONS, ActionReadBudgetTracker, AnnotationAppearanceReader, AnnotationFlattener, AnnotationMutator, AnnotationReader, AttachmentMutator, AttachmentReader, BaseDocumentRegistry, CloseStack, DocumentActionsReader, PagesMutator as DocumentPagesMutator, PagesMutator, DocumentSaver, DocumentSession, EPDF_CHAR_GEOMETRY_LAYOUT, EventHub, FontRegistrar, FormMutator, FormReader, FormsEffectsApplier, LocalRevisionAuthority, MetadataMutator, MetadataReader, PageGeometryReader, PagesReader as PageLayoutReader, PagesReader, PagePtrPool, PageRenderReader as PageRasterReader, PageRenderReader, PageTextReader, PagesExtractor, PagesFlattener, PagesInserter, RawAnnotationReader, RedactionApplier, SearchReader, SecurityReader, SessionEventPublisher, WorkerHost, buildRunsFromRawGlyphs, computeMutationImpact, destroyLibrary, disposeFormModel, ensureInitialized, formatPdfDate, generateUuid, hasAllStandardSecurityPermissions, normalizeU32, openFatMemoryDocument, openLayerDocument, pdfDateToIso, readActionModel, readAttachmentFileInfo, throwIfAborted, writeAttachmentFilePayload };
|
|
10327
10752
|
|
|
10328
10753
|
//# sourceMappingURL=index.js.map
|