@poe-platform/safe-bash 0.1.762 → 0.1.764

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/image-ast/index.browser.js +454 -208
  2. package/dist/image-ast/index.js +454 -208
  3. package/dist/pdf-ast/ast.d.ts +23 -0
  4. package/dist/pdf-ast/index.js +543 -244
  5. package/dist/safe-bash/chunks/{chunk-CRQDMBQA.js → chunk-FSH7QRIC.js} +10 -1
  6. package/dist/safe-bash/command-chunks/{chunk-D4GXXV65.js → chunk-B7YLGJRF.js} +2 -2
  7. package/dist/safe-bash/command-chunks/{chunk-P3Q2QSCA.js → chunk-G3IIEU2N.js} +457 -208
  8. package/dist/safe-bash/command-chunks/{chunk-F7MJRXQ2.js → chunk-RDPJGIQF.js} +1 -1
  9. package/dist/safe-bash/commands/python/index.browser.js +1 -1
  10. package/dist/safe-bash/commands/python/llm-module.js +3 -1
  11. package/dist/safe-bash/commands/python/shell-module.js +7 -0
  12. package/dist/safe-bash/core.browser.js +33 -13
  13. package/dist/safe-bash/shell/runtime.js +44 -12
  14. package/dist/safe-bash-checksum-engine/index.d.ts +1 -1
  15. package/dist/safe-bash-checksum-engine/index.js +5 -1
  16. package/dist/safe-bash-command-ffmpeg/index.js +7476 -7338
  17. package/dist/safe-bash-command-gh/index.js +174 -105
  18. package/dist/safe-bash-command-imagemagick/index.js +2 -2
  19. package/dist/safe-bash-command-pandoc/command.js +3 -3
  20. package/dist/safe-bash-command-pandoc/index.js +3 -3
  21. package/dist/safe-bash-command-pdfimages/index.js +454 -208
  22. package/dist/safe-bash-command-pdfinfo/index.js +541 -244
  23. package/dist/safe-bash-command-pdftk/index.js +454 -208
  24. package/dist/safe-bash-command-pdftoppm/index.js +541 -244
  25. package/dist/safe-bash-command-pdftotext/index.js +454 -208
  26. package/dist/safe-bash-command-qpdf/index.js +454 -208
  27. package/dist/safe-bash-command-sips/index.js +2 -2
  28. package/dist/safe-bash-command-soffice/index.js +1 -1
  29. package/dist/safe-bash-command-ssconvert/index.js +514 -208
  30. package/dist/safe-bash-command-wkhtmltopdf/index.js +455 -208
  31. package/dist/safe-playwright-cloudflare/browser-snapshot-labels.d.ts +14 -0
  32. package/dist/safe-playwright-cloudflare/browser-snapshot-labels.js +62 -0
  33. package/dist/safe-playwright-cloudflare/browser-snapshot-scheduler.js +8 -1
  34. package/package.json +2 -2
  35. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +27 -0
@@ -32076,14 +32076,18 @@ function evaluateContentStreamToDisplayList(params) {
32076
32076
  const paths = [];
32077
32077
  const images = [];
32078
32078
  const operations = [];
32079
+ let capturedOperations;
32080
+ let insideSoftMask = false;
32079
32081
  const emit = (operation) => {
32080
- const { clipPaths, clipImages } = curState();
32081
- if (clipPaths || clipImages) operation = { ...operation, value: {
32082
+ const { clipPaths, clipImages, softMask } = curState();
32083
+ if (clipPaths || clipImages || softMask) operation = { ...operation, value: {
32082
32084
  ...operation.value,
32083
32085
  ...clipPaths ? { clipPaths } : {},
32084
- ...clipImages ? { clipImages } : {}
32086
+ ...clipImages ? { clipImages } : {},
32087
+ ...softMask ? { softMask } : {}
32085
32088
  } };
32086
- operations.push(operation);
32089
+ (capturedOperations ?? operations).push(operation);
32090
+ if (insideSoftMask) return;
32087
32091
  switch (operation.kind) {
32088
32092
  case "path":
32089
32093
  paths.push(operation.value);
@@ -32189,7 +32193,7 @@ function evaluateContentStreamToDisplayList(params) {
32189
32193
  );
32190
32194
  return { r: kClamp(r), g: kClamp(g), b: kClamp(b) };
32191
32195
  };
32192
- const applyStateOperator = (st, operator, ops, activeResources) => {
32196
+ const applyStateOperator = (st, operator, ops, activeResources, activeFonts, depth) => {
32193
32197
  const num = (i, fb = 0) => ops[i]?.kind === "number" ? ops[i].value : fb;
32194
32198
  if (operator === "cm") {
32195
32199
  const m = [num(0, 1), num(1, 0), num(2, 0), num(3, 1), num(4, 0), num(5, 0)];
@@ -32272,6 +32276,46 @@ function evaluateContentStreamToDisplayList(params) {
32272
32276
  const extDict = params.cosDoc.resolveDict(dictGet(activeResources, "ExtGState"));
32273
32277
  const gsDict = extDict ? params.cosDoc.resolveDict(dictGet(extDict, ops[0].decoded)) : void 0;
32274
32278
  if (gsDict) {
32279
+ const mask = params.cosDoc.resolve(dictGet(gsDict, "SMask"));
32280
+ if (mask?.kind === "name" && mask.decoded === "None") {
32281
+ st.softMask = void 0;
32282
+ } else if (mask?.kind === "dict") {
32283
+ const subtype = params.cosDoc.resolve(dictGet(mask, "S"));
32284
+ const form = params.cosDoc.resolve(dictGet(mask, "G"));
32285
+ if (form?.kind === "stream" && subtype?.kind === "name" && (subtype.decoded === "Alpha" || subtype.decoded === "Luminosity")) {
32286
+ if (depth >= 8) throw new PdfError("E_LIMIT", "Soft-mask nesting exceeds the form depth limit");
32287
+ const parentOperations = capturedOperations;
32288
+ const parentInsideSoftMask = insideSoftMask;
32289
+ const savedTextState = { pendingTextClip, hasTextClip, activeTm, activeTlm };
32290
+ const captured = [];
32291
+ capturedOperations = captured;
32292
+ insideSoftMask = true;
32293
+ const maskState = { ...st, softMask: void 0, fillAlpha: 1, strokeAlpha: 1, blendMode: "Normal" };
32294
+ delete maskState.clipPaths;
32295
+ delete maskState.clipImages;
32296
+ delete maskState.clipRect;
32297
+ stateStack.push(maskState);
32298
+ try {
32299
+ paintForm(form, activeResources, activeFonts, depth, void 0, void 0, true);
32300
+ } finally {
32301
+ stateStack.pop();
32302
+ capturedOperations = parentOperations;
32303
+ insideSoftMask = parentInsideSoftMask;
32304
+ ({ pendingTextClip, hasTextClip, activeTm, activeTlm } = savedTextState);
32305
+ }
32306
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
32307
+ const colorSpace = group ? dictGet(group, "CS") : void 0;
32308
+ const bc = params.cosDoc.resolveArray(dictGet(mask, "BC"));
32309
+ const components = bc?.items.map((item) => {
32310
+ const value = params.cosDoc.resolve(item);
32311
+ return value?.kind === "number" ? value.value : 0;
32312
+ });
32313
+ const [r, g, b] = components ? convertColorSpaceComponentsToRgb(params.cosDoc, colorSpace, "DeviceRGB", components, activeResources) : [0, 0, 0];
32314
+ const transfer = params.cosDoc.resolve(dictGet(mask, "TR"));
32315
+ const transferMap = transfer?.kind === "dict" || transfer?.kind === "stream" ? Uint8Array.from({ length: 256 }, (_, i) => Math.floor(kClamp(Math.fround(evalShadingFunctionToComponents(params.cosDoc, transfer, Math.fround(i / 255))[0] ?? 0)) * 255)) : void 0;
32316
+ st.softMask = { subtype: subtype.decoded, operations: captured, backdrop: { r, g, b }, transferMap };
32317
+ }
32318
+ }
32275
32319
  const bmNode = params.cosDoc.resolve(dictGet(gsDict, "BM"));
32276
32320
  if (bmNode?.kind === "name") {
32277
32321
  st.blendMode = bmNode.decoded === "Compatible" ? "Normal" : bmNode.decoded;
@@ -32358,6 +32402,84 @@ function evaluateContentStreamToDisplayList(params) {
32358
32402
  ] }], void 0, void 0, resources, activeFonts, depth);
32359
32403
  stateStack.pop();
32360
32404
  };
32405
+ const paintForm = (form, activeResources, activeFonts, depth, mcid, actualText, maskGroup = false) => {
32406
+ const st = curState();
32407
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
32408
+ const groupType = group ? params.cosDoc.resolve(dictGet(group, "S")) : void 0;
32409
+ const isolated = group ? params.cosDoc.resolve(dictGet(group, "I")) : void 0;
32410
+ const isolate = !maskGroup && groupType?.kind === "name" && groupType.decoded === "Transparency" && isolated?.kind === "boolean" && isolated.value;
32411
+ const formStreamBytes = params.cosDoc.decodeStream(form);
32412
+ const formNodes = parseContentStream(formStreamBytes);
32413
+ const formResDict = params.cosDoc.resolveDict(dictGet(form.dict, "Resources")) ?? activeResources;
32414
+ const formFonts = new Map(activeFonts);
32415
+ for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
32416
+ formFonts.set(k, v);
32417
+ }
32418
+ let nextCtm = [...st.ctm];
32419
+ const matArr = params.cosDoc.resolveArray(dictGet(form.dict, "Matrix"));
32420
+ if (matArr && matArr.items.length >= 6) {
32421
+ const mn = (idx, fb = 0) => {
32422
+ const resolved = params.cosDoc.resolve(matArr.items[idx]);
32423
+ return resolved?.kind === "number" ? resolved.value : fb;
32424
+ };
32425
+ const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
32426
+ nextCtm = multiplyMatrices(formMat, nextCtm);
32427
+ }
32428
+ let nextClip = !isolate && st.clipRect ? [...st.clipRect] : void 0;
32429
+ let nextClipPaths = isolate ? void 0 : st.clipPaths;
32430
+ const bboxArr = params.cosDoc.resolveArray(dictGet(form.dict, "BBox"));
32431
+ if (bboxArr && bboxArr.items.length >= 4) {
32432
+ const bn = (idx, fb = 0) => {
32433
+ const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
32434
+ return resolved?.kind === "number" ? resolved.value : fb;
32435
+ };
32436
+ const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
32437
+ const pts = [
32438
+ transformPoint(nextCtm, bx0, by0),
32439
+ transformPoint(nextCtm, bx1, by0),
32440
+ transformPoint(nextCtm, bx1, by1),
32441
+ transformPoint(nextCtm, bx0, by1)
32442
+ ];
32443
+ nextClipPaths = [...nextClipPaths ?? [], [
32444
+ ...pts.map(([x, y], index) => ({ kind: index === 0 ? "move" : "line", x, y })),
32445
+ { kind: "close" }
32446
+ ]];
32447
+ const fMinX = Math.min(...pts.map((p) => p[0]));
32448
+ const fMinY = Math.min(...pts.map((p) => p[1]));
32449
+ const fMaxX = Math.max(...pts.map((p) => p[0]));
32450
+ const fMaxY = Math.max(...pts.map((p) => p[1]));
32451
+ if (fMaxX > fMinX && fMaxY > fMinY) {
32452
+ nextClip = nextClip ? [
32453
+ Math.max(nextClip[0], fMinX),
32454
+ Math.max(nextClip[1], fMinY),
32455
+ Math.min(nextClip[2], fMaxX),
32456
+ Math.min(nextClip[3], fMaxY)
32457
+ ] : [fMinX, fMinY, fMaxX, fMaxY];
32458
+ }
32459
+ }
32460
+ const parentOperations = capturedOperations;
32461
+ const children = [];
32462
+ const nextState = { ...st, ctm: nextCtm };
32463
+ if (isolate) {
32464
+ capturedOperations = children;
32465
+ nextState.fillAlpha = nextState.strokeAlpha = 1;
32466
+ nextState.blendMode = "Normal";
32467
+ nextState.softMask = void 0;
32468
+ delete nextState.clipImages;
32469
+ delete nextState.clipPaths;
32470
+ delete nextState.clipRect;
32471
+ }
32472
+ if (nextClip) nextState.clipRect = nextClip;
32473
+ if (nextClipPaths) nextState.clipPaths = nextClipPaths;
32474
+ stateStack.push(nextState);
32475
+ try {
32476
+ walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
32477
+ } finally {
32478
+ stateStack.pop();
32479
+ capturedOperations = parentOperations;
32480
+ }
32481
+ if (isolate) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
32482
+ };
32361
32483
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
32362
32484
  for (const node of nodes) {
32363
32485
  switch (node.kind) {
@@ -32402,7 +32524,7 @@ function evaluateContentStreamToDisplayList(params) {
32402
32524
  break;
32403
32525
  }
32404
32526
  case "state-op": {
32405
- applyStateOperator(curState(), node.operator, node.operands, activeResources);
32527
+ applyStateOperator(curState(), node.operator, node.operands, activeResources, activeFonts, depth);
32406
32528
  break;
32407
32529
  }
32408
32530
  case "path-op": {
@@ -32688,53 +32810,7 @@ function evaluateContentStreamToDisplayList(params) {
32688
32810
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
32689
32811
  }, patternMask, activeResources, activeFonts, depth);
32690
32812
  } else if (sub === "Form" && depth < 8) {
32691
- const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
32692
- const formNodes = parseContentStream(formStreamBytes);
32693
- const formResDict = params.cosDoc.resolveDict(dictGet(xobjNode.dict, "Resources")) ?? activeResources;
32694
- const formFonts = new Map(activeFonts);
32695
- for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
32696
- formFonts.set(k, v);
32697
- }
32698
- let nextCtm = [...st.ctm];
32699
- const matArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "Matrix"));
32700
- if (matArr && matArr.items.length >= 6) {
32701
- const mn = (idx, fb = 0) => {
32702
- const resolved = params.cosDoc.resolve(matArr.items[idx]);
32703
- return resolved?.kind === "number" ? resolved.value : fb;
32704
- };
32705
- const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
32706
- nextCtm = multiplyMatrices(formMat, nextCtm);
32707
- }
32708
- let nextClip = st.clipRect ? [...st.clipRect] : void 0;
32709
- const bboxArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "BBox"));
32710
- if (bboxArr && bboxArr.items.length >= 4) {
32711
- const bn = (idx, fb = 0) => {
32712
- const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
32713
- return resolved?.kind === "number" ? resolved.value : fb;
32714
- };
32715
- const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
32716
- const pts = [
32717
- transformPoint(nextCtm, bx0, by0),
32718
- transformPoint(nextCtm, bx1, by0),
32719
- transformPoint(nextCtm, bx0, by1),
32720
- transformPoint(nextCtm, bx1, by1)
32721
- ];
32722
- const fMinX = Math.min(...pts.map((p) => p[0]));
32723
- const fMinY = Math.min(...pts.map((p) => p[1]));
32724
- const fMaxX = Math.max(...pts.map((p) => p[0]));
32725
- const fMaxY = Math.max(...pts.map((p) => p[1]));
32726
- if (fMaxX > fMinX && fMaxY > fMinY) {
32727
- nextClip = nextClip ? [
32728
- Math.max(nextClip[0], fMinX),
32729
- Math.max(nextClip[1], fMinY),
32730
- Math.min(nextClip[2], fMaxX),
32731
- Math.min(nextClip[3], fMaxY)
32732
- ] : [fMinX, fMinY, fMaxX, fMaxY];
32733
- }
32734
- }
32735
- stateStack.push({ ...st, ctm: nextCtm, ...nextClip ? { clipRect: nextClip } : {} });
32736
- walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
32737
- if (stateStack.length > 1) stateStack.pop();
32813
+ paintForm(xobjNode, activeResources, activeFonts, depth, mcid, actualText);
32738
32814
  }
32739
32815
  }
32740
32816
  }
@@ -32953,7 +33029,7 @@ function evaluateContentStreamToDisplayList(params) {
32953
33029
  st.textRenderMode = cmd.mode;
32954
33030
  break;
32955
33031
  case "state-op":
32956
- applyStateOperator(st, cmd.operator, cmd.operands, activeResources);
33032
+ applyStateOperator(st, cmd.operator, cmd.operands, activeResources, activeFonts, depth);
32957
33033
  break;
32958
33034
  case "show-text":
32959
33035
  emitTokenBytes(cmd.token.bytes);
@@ -34046,6 +34122,187 @@ function downscaleImage(image, widthScale, heightScale) {
34046
34122
  return image;
34047
34123
  }
34048
34124
 
34125
+ // packages/pdf-ast/src/render/stroke.ts
34126
+ init_buffer();
34127
+ var MAX_STROKE_VERTICES = 1e6;
34128
+ function dashSubpath(path, pattern, phase) {
34129
+ const cycle = pattern.reduce((sum, value) => sum + value, 0);
34130
+ if (!(cycle > 0)) return [path];
34131
+ let offset = (phase % cycle + cycle) % cycle, index = 0;
34132
+ while (offset > 0) {
34133
+ if (offset < pattern[index]) break;
34134
+ offset -= pattern[index];
34135
+ index = (index + 1) % pattern.length;
34136
+ }
34137
+ let remaining = pattern[index] - offset;
34138
+ const points = path.closed ? [...path.points, path.points[0]] : path.points;
34139
+ const result = [];
34140
+ let current = [];
34141
+ let steps = 0;
34142
+ const flush = () => {
34143
+ if (current.length) result.push({ points: current, closed: false });
34144
+ current = [];
34145
+ };
34146
+ const advance = (point) => {
34147
+ while (remaining <= 0) {
34148
+ if (++steps > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
34149
+ if (index % 2 === 0) {
34150
+ if (pattern[index] === 0) result.push({ points: [point, point], closed: false });
34151
+ flush();
34152
+ }
34153
+ index = (index + 1) % pattern.length;
34154
+ remaining = pattern[index];
34155
+ }
34156
+ };
34157
+ for (let i = 1; i < points.length; i++) {
34158
+ const start = points[i - 1], end = points[i];
34159
+ const dx = end[0] - start[0], dy = end[1] - start[1];
34160
+ const length = Math.hypot(dx, dy);
34161
+ if (!Number.isFinite(length) || length / cycle * pattern.length > MAX_STROKE_VERTICES) {
34162
+ throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
34163
+ }
34164
+ let distance = 0;
34165
+ while (distance < length) {
34166
+ const point = [start[0] + dx * distance / length, start[1] + dy * distance / length];
34167
+ advance(point);
34168
+ const step = Math.min(remaining, length - distance);
34169
+ if (distance + step === distance || ++steps > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
34170
+ distance += step;
34171
+ remaining -= step;
34172
+ if (index % 2 === 0) {
34173
+ if (!current.length) current.push(point);
34174
+ current.push([start[0] + dx * distance / length, start[1] + dy * distance / length]);
34175
+ }
34176
+ }
34177
+ }
34178
+ flush();
34179
+ if (path.closed && result.length) {
34180
+ const first = result[0], last = result[result.length - 1];
34181
+ const start = path.points[0];
34182
+ const firstPoint = first.points[0], lastPoint = last.points[last.points.length - 1];
34183
+ if (firstPoint[0] === start[0] && firstPoint[1] === start[1] && lastPoint[0] === start[0] && lastPoint[1] === start[1]) {
34184
+ if (first === last) result[0] = { points: first.points, closed: true };
34185
+ else {
34186
+ result[0] = { points: [...last.points, ...first.points.slice(1)], closed: false };
34187
+ result.pop();
34188
+ }
34189
+ }
34190
+ }
34191
+ return result;
34192
+ }
34193
+ function strokeOutlines(paths, width, cap, join, miterLimit, dashArray = [], dashPhase = 0) {
34194
+ const half = width / 2;
34195
+ const contours = [];
34196
+ const pattern = dashArray.length % 2 ? [...dashArray, ...dashArray] : dashArray;
34197
+ let count = 0;
34198
+ let contour = [];
34199
+ const add = (x, y) => {
34200
+ if (++count > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke outline exceeds the vertex limit");
34201
+ contour.push([x, y]);
34202
+ };
34203
+ const arc = (point, dx1, dy1, dx2, dy2) => {
34204
+ let a1 = Math.atan2(dy1, dx1), a2 = Math.atan2(dy2, dx2);
34205
+ const ccw = a1 - a2 > 0 && a1 - a2 < Math.PI;
34206
+ const step = Math.acos(half / (half + 0.125)) * 2;
34207
+ add(point[0] + dx1, point[1] + dy1);
34208
+ if (step > 0) {
34209
+ if (!ccw) {
34210
+ if (a1 > a2) a2 += 2 * Math.PI;
34211
+ a2 -= step / 4;
34212
+ if ((a2 - a1) / step > MAX_STROKE_VERTICES - count) throw new PdfError("E_LIMIT", "Stroke arc exceeds the vertex limit");
34213
+ for (a1 += step; a1 < a2; a1 += step) add(point[0] + half * Math.cos(a1), point[1] + half * Math.sin(a1));
34214
+ } else {
34215
+ if (a1 < a2) a2 -= 2 * Math.PI;
34216
+ a2 += step / 4;
34217
+ if ((a1 - a2) / step > MAX_STROKE_VERTICES - count) throw new PdfError("E_LIMIT", "Stroke arc exceeds the vertex limit");
34218
+ for (a1 -= step; a1 > a2; a1 -= step) add(point[0] + half * Math.cos(a1), point[1] + half * Math.sin(a1));
34219
+ }
34220
+ }
34221
+ add(point[0] + dx2, point[1] + dy2);
34222
+ };
34223
+ const addCap = (point, next) => {
34224
+ const length = Math.hypot(next[0] - point[0], next[1] - point[1]);
34225
+ const dx = half * (next[1] - point[1]) / length;
34226
+ const dy = half * (next[0] - point[0]) / length;
34227
+ if (cap !== 1) {
34228
+ const sx = cap === 2 ? dy : 0, sy = cap === 2 ? dx : 0;
34229
+ add(point[0] - dx - sx, point[1] + dy - sy);
34230
+ add(point[0] + dx - sx, point[1] - dy - sy);
34231
+ } else {
34232
+ const angle = Math.atan2(dy, -dx);
34233
+ const step = Math.max(1e-3, Math.acos(half / (half + 0.125)) * 2);
34234
+ add(point[0] - dx, point[1] + dy);
34235
+ for (let a = angle + step; a < angle + Math.PI - step / 4; a += step) add(point[0] + half * Math.cos(a), point[1] + half * Math.sin(a));
34236
+ add(point[0] + dx, point[1] - dy);
34237
+ }
34238
+ };
34239
+ const addJoin = (prev, point, next) => {
34240
+ const len1 = Math.hypot(point[0] - prev[0], point[1] - prev[1]);
34241
+ const len2 = Math.hypot(next[0] - point[0], next[1] - point[1]);
34242
+ const dx1 = half * (point[1] - prev[1]) / len1, dy1 = half * (point[0] - prev[0]) / len1;
34243
+ const dx2 = half * (next[1] - point[1]) / len2, dy2 = half * (next[0] - point[0]) / len2;
34244
+ const inner = (next[0] - point[0]) * (point[1] - prev[1]) - (next[1] - point[1]) * (point[0] - prev[0]) > 0;
34245
+ if (!inner && join === 1) {
34246
+ arc(point, dx1, -dy1, dx2, -dy2);
34247
+ return;
34248
+ }
34249
+ if (inner || join === 0) {
34250
+ const ax = prev[0] + dx1, ay = prev[1] - dy1;
34251
+ const bx = point[0] + dx1, by = point[1] - dy1;
34252
+ const cx = point[0] + dx2, cy = point[1] - dy2;
34253
+ const dx = next[0] + dx2, dy = next[1] - dy2;
34254
+ const den = (bx - ax) * (dy - cy) - (by - ay) * (dx - cx);
34255
+ if (Math.abs(den) >= 1e-30) {
34256
+ const t = ((ay - cy) * (dx - cx) - (ax - cx) * (dy - cy)) / den;
34257
+ const x = ax + (bx - ax) * t, y = ay + (by - ay) * t;
34258
+ if (Math.hypot(x - point[0], y - point[1]) <= half * (inner ? 1.01 : miterLimit)) {
34259
+ add(x, y);
34260
+ return;
34261
+ }
34262
+ } else if ((bx - prev[0]) * dy1 - (prev[1] - by) * dx1 < 0 !== (bx - next[0]) * dy1 - (next[1] - by) * dx1 < 0) {
34263
+ add(bx, by);
34264
+ return;
34265
+ }
34266
+ }
34267
+ add(point[0] + dx1, point[1] - dy1);
34268
+ add(point[0] + dx2, point[1] - dy2);
34269
+ };
34270
+ for (const path of paths) {
34271
+ for (const subpath of pattern.length ? dashSubpath(path, pattern, dashPhase) : [path]) {
34272
+ const points = [];
34273
+ for (const point of subpath.points) {
34274
+ const prev = points[points.length - 1];
34275
+ if (!prev || Math.hypot(prev[0] - point[0], prev[1] - point[1]) > 1e-14) points.push(point);
34276
+ }
34277
+ let closed = subpath.closed;
34278
+ if (closed && points.length > 1 && Math.hypot(points[0][0] - points[points.length - 1][0], points[0][1] - points[points.length - 1][1]) <= 1e-14) points.pop();
34279
+ if (points.length < 3) closed = false;
34280
+ if (points.length === 1 && subpath.points.length > 1 && cap === 1) {
34281
+ contour = [];
34282
+ const [x, y] = points[0];
34283
+ addCap([x, y], [x + 1, y]);
34284
+ addCap([x, y], [x - 1, y]);
34285
+ contours.push(contour);
34286
+ } else if (points.length >= 2) {
34287
+ contour = [];
34288
+ if (!closed) addCap(points[0], points[1]);
34289
+ for (let i = closed ? 0 : 1; i < points.length - (closed ? 0 : 1); i++) {
34290
+ addJoin(points[(i + points.length - 1) % points.length], points[i], points[(i + 1) % points.length]);
34291
+ }
34292
+ if (closed) {
34293
+ contours.push(contour);
34294
+ contour = [];
34295
+ } else addCap(points[points.length - 1], points[points.length - 2]);
34296
+ for (let i = points.length - (closed ? 1 : 2); i >= (closed ? 0 : 1); i--) {
34297
+ addJoin(points[(i + 1) % points.length], points[i], points[(i + points.length - 1) % points.length]);
34298
+ }
34299
+ contours.push(contour);
34300
+ }
34301
+ }
34302
+ }
34303
+ return contours;
34304
+ }
34305
+
34049
34306
  // packages/pdf-ast/src/render/raster.ts
34050
34307
  function encodePng(bitmap) {
34051
34308
  return encodeRgbaToPng(bitmap.width, bitmap.height, bitmap.data);
@@ -34744,111 +35001,60 @@ function blendPixel(rgba, width, height, px, py, color, alpha, blendMode, clipMa
34744
35001
  rgba[idx + 2] = Math.round((effB * a + cbB * dstA * (1 - a)) / outA * 255);
34745
35002
  rgba[idx + 3] = Math.round(outA * 255);
34746
35003
  }
34747
- function drawAntiAliasedSegment(rgba, width, height, x0, y0, x1, y1, strokeWidth, color, alpha = 1, lineCap = 0, antialias = true, blendMode, clipMask) {
34748
- const halfW = Math.max(0.6, strokeWidth * 0.5);
34749
- const dx = x1 - x0;
34750
- const dy = y1 - y0;
34751
- const lenSq = dx * dx + dy * dy;
34752
- const segLen = Math.sqrt(lenSq);
34753
- const pad = lineCap === 2 ? halfW + 2 : halfW + 1;
34754
- const minX = Math.max(0, Math.floor(Math.min(x0, x1) - pad));
34755
- const maxX = Math.min(width - 1, Math.ceil(Math.max(x0, x1) + pad));
34756
- const minY = Math.max(0, Math.floor(Math.min(y0, y1) - pad));
34757
- const maxY = Math.min(height - 1, Math.ceil(Math.max(y0, y1) + pad));
34758
- for (let py = minY; py <= maxY; py++) {
34759
- for (let px = minX; px <= maxX; px++) {
34760
- const cx = px + 0.5;
34761
- const cy = py + 0.5;
34762
- if (segLen > 1e-6 && (lineCap === 0 || lineCap === 2)) {
34763
- const ux = dx / segLen;
34764
- const uy = dy / segLen;
34765
- const along = (cx - x0) * ux + (cy - y0) * uy;
34766
- const perp = Math.abs(-(cx - x0) * uy + (cy - y0) * ux);
34767
- const minAlong = lineCap === 2 ? -halfW : 0;
34768
- const maxAlong = lineCap === 2 ? segLen + halfW : segLen;
34769
- const overAlong = along < minAlong ? minAlong - along : along > maxAlong ? along - maxAlong : 0;
34770
- const dist2 = overAlong > 0 ? Math.max(perp, halfW + overAlong) : perp;
34771
- if (dist2 <= halfW + 0.75) {
34772
- const cov = antialias ? Math.max(0, Math.min(1, halfW + 0.5 - dist2)) : dist2 <= halfW + 0.25 ? 1 : 0;
34773
- blendPixel(rgba, width, height, px, py, color, cov * alpha, blendMode, clipMask);
34774
- }
34775
- continue;
34776
- }
34777
- let t = lenSq > 1e-6 ? ((cx - x0) * dx + (cy - y0) * dy) / lenSq : 0;
34778
- t = Math.max(0, Math.min(1, t));
34779
- const projX = x0 + t * dx;
34780
- const projY = y0 + t * dy;
34781
- const dist = Math.hypot(cx - projX, cy - projY);
34782
- if (dist <= halfW + 0.75) {
34783
- const cov = antialias ? Math.max(0, Math.min(1, halfW + 0.5 - dist)) : dist <= halfW + 0.25 ? 1 : 0;
34784
- blendPixel(rgba, width, height, px, py, color, cov * alpha, blendMode, clipMask);
34785
- }
34786
- }
34787
- }
34788
- }
34789
- function segmentsToScreenEdges(segments, pageHeight, scale, closeSubpaths = false) {
34790
- const edges = [];
34791
- let curX = 0;
34792
- let curY = 0;
34793
- let startX = 0;
34794
- let startY = 0;
34795
- let hasOpenSubpath = false;
35004
+ function segmentsToScreenPaths(segments, pageHeight, scale) {
35005
+ const paths = [];
35006
+ let points = [];
35007
+ let current = [0, 0];
34796
35008
  const toScreen = (x, y) => [x * scale, (pageHeight - y) * scale];
34797
- for (const seg of segments) {
34798
- if (seg.kind === "move") {
34799
- if (closeSubpaths && hasOpenSubpath && (curX !== startX || curY !== startY)) {
34800
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
34801
- }
34802
- [curX, curY] = toScreen(seg.x, seg.y);
34803
- startX = curX;
34804
- startY = curY;
34805
- hasOpenSubpath = false;
34806
- } else if (seg.kind === "line") {
34807
- const [nx, ny] = toScreen(seg.x, seg.y);
34808
- edges.push({ x0: curX, y0: curY, x1: nx, y1: ny });
34809
- curX = nx;
34810
- curY = ny;
34811
- hasOpenSubpath = true;
34812
- } else if (seg.kind === "cubic") {
34813
- const [p1x, p1y] = toScreen(seg.x1, seg.y1);
34814
- const [p2x, p2y] = toScreen(seg.x2, seg.y2);
34815
- const [p3x, p3y] = toScreen(seg.x, seg.y);
34816
- const points = flattenCubic(curX, curY, p1x, p1y, p2x, p2y, p3x, p3y);
34817
- let px = curX;
34818
- let py = curY;
34819
- for (let i = 1; i < points.length; i++) {
34820
- const [qx, qy] = points[i];
34821
- edges.push({ x0: px, y0: py, x1: qx, y1: qy });
34822
- px = qx;
34823
- py = qy;
34824
- }
34825
- curX = p3x;
34826
- curY = p3y;
34827
- hasOpenSubpath = true;
34828
- } else if (seg.kind === "close") {
34829
- if (curX !== startX || curY !== startY) {
34830
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
34831
- curX = startX;
34832
- curY = startY;
34833
- }
34834
- hasOpenSubpath = false;
34835
- } else if (seg.kind === "rect") {
34836
- if (closeSubpaths && hasOpenSubpath && (curX !== startX || curY !== startY)) {
34837
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
34838
- }
34839
- const [rx0, ry0] = toScreen(seg.x, seg.y);
34840
- const [rx1, ry1] = toScreen(seg.x + seg.width, seg.y + seg.height);
34841
- edges.push(
34842
- { x0: rx0, y0: ry0, x1: rx1, y1: ry0 },
34843
- { x0: rx1, y0: ry0, x1: rx1, y1: ry1 },
34844
- { x0: rx1, y0: ry1, x1: rx0, y1: ry1 },
34845
- { x0: rx0, y0: ry1, x1: rx0, y1: ry0 }
34846
- );
34847
- hasOpenSubpath = false;
35009
+ for (const segment of segments) {
35010
+ if (segment.kind === "move") {
35011
+ if (points.length) paths.push({ points, closed: false });
35012
+ current = toScreen(segment.x, segment.y);
35013
+ points = [current];
35014
+ } else if (segment.kind === "line") {
35015
+ if (!points.length) points = [current];
35016
+ current = toScreen(segment.x, segment.y);
35017
+ points.push(current);
35018
+ } else if (segment.kind === "cubic") {
35019
+ if (!points.length) points = [current];
35020
+ const a = toScreen(segment.x1, segment.y1), b = toScreen(segment.x2, segment.y2);
35021
+ const end = toScreen(segment.x, segment.y);
35022
+ const curve = flattenCubic(current[0], current[1], a[0], a[1], b[0], b[1], end[0], end[1]);
35023
+ for (let i = 1; i < curve.length; i++) points.push(curve[i]);
35024
+ current = end;
35025
+ } else if (segment.kind === "close") {
35026
+ if (points.length) {
35027
+ paths.push({ points, closed: true });
35028
+ current = points[0];
35029
+ points = [];
35030
+ }
35031
+ } else if (segment.kind === "rect") {
35032
+ if (points.length) paths.push({ points, closed: false });
35033
+ const first = toScreen(segment.x, segment.y);
35034
+ paths.push({ points: [
35035
+ first,
35036
+ toScreen(segment.x + segment.width, segment.y),
35037
+ toScreen(segment.x + segment.width, segment.y + segment.height),
35038
+ toScreen(segment.x, segment.y + segment.height)
35039
+ ], closed: true });
35040
+ current = first;
35041
+ points = [];
35042
+ }
35043
+ }
35044
+ if (points.length) paths.push({ points, closed: false });
35045
+ return paths;
35046
+ }
35047
+ function pathsToEdges(paths, closeSubpaths = false) {
35048
+ const edges = [];
35049
+ for (const { points, closed } of paths) {
35050
+ for (let i = 1; i < points.length; i++) {
35051
+ const a = points[i - 1], b = points[i];
35052
+ edges.push({ x0: a[0], y0: a[1], x1: b[0], y1: b[1] });
35053
+ }
35054
+ if ((closed || closeSubpaths) && points.length > 1) {
35055
+ const a = points[points.length - 1], b = points[0];
35056
+ edges.push({ x0: a[0], y0: a[1], x1: b[0], y1: b[1] });
34848
35057
  }
34849
- }
34850
- if (closeSubpaths && hasOpenSubpath && (curX !== startX || curY !== startY)) {
34851
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
34852
35058
  }
34853
35059
  return edges;
34854
35060
  }
@@ -34959,6 +35165,30 @@ function paintOperations(displayList) {
34959
35165
  ...displayList.glyphs.map((value) => ({ kind: "glyph", value }))
34960
35166
  ];
34961
35167
  }
35168
+ function renderSoftMask(mask, displayList, scale) {
35169
+ const bitmap = renderDisplayListToBitmap({
35170
+ ...displayList,
35171
+ rotation: 0,
35172
+ glyphs: [],
35173
+ paths: [],
35174
+ images: [],
35175
+ operations: mask.operations
35176
+ }, { scale, transparent: true });
35177
+ const { data } = bitmap;
35178
+ for (let i = 0; i < data.length; i += 4) {
35179
+ let value = data[i + 3];
35180
+ if (mask.subtype === "Luminosity") {
35181
+ const alpha = value / 255;
35182
+ const r = Math.round(data[i] * alpha + mask.backdrop.r * 255 * (1 - alpha));
35183
+ const g = Math.round(data[i + 1] * alpha + mask.backdrop.g * 255 * (1 - alpha));
35184
+ const b = Math.round(data[i + 2] * alpha + mask.backdrop.b * 255 * (1 - alpha));
35185
+ value = Math.round(pdfLum(r, g, b));
35186
+ }
35187
+ data[i] = data[i + 1] = data[i + 2] = 0;
35188
+ data[i + 3] = mask.transferMap?.[value] ?? value;
35189
+ }
35190
+ return bitmap;
35191
+ }
34962
35192
  function renderDisplayListToBitmap(displayList, options = {}) {
34963
35193
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
34964
35194
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -34982,10 +35212,28 @@ function renderDisplayListToBitmap(displayList, options = {}) {
34982
35212
  const aaTxt = options.antialiasText !== false;
34983
35213
  let cachedClips;
34984
35214
  let cachedClipMask;
35215
+ let cachedSoftMask;
35216
+ let cachedSoftMaskPixels;
34985
35217
  const imageClipMasks = /* @__PURE__ */ new Map();
34986
35218
  for (const original of paintOperations(displayList)) {
34987
35219
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
34988
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
35220
+ let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
35221
+ if (operation.kind === "group") {
35222
+ const group = operation.value;
35223
+ const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations: group.operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, transparent: true });
35224
+ for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
35225
+ operation = { kind: "image", value: {
35226
+ name: "TransparencyGroup",
35227
+ width: bitmap.width,
35228
+ height: bitmap.height,
35229
+ decodedRgba: bitmap.data,
35230
+ matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, 0, displayList.height - bitmap.height / scale],
35231
+ colorSpace: "DeviceRGB",
35232
+ bitsPerComponent: 8,
35233
+ blendMode: group.blendMode,
35234
+ clipRect: group.clipRect
35235
+ } };
35236
+ }
34989
35237
  const clips = original.value.clipPaths;
34990
35238
  let clipMask = clips && clips === cachedClips ? cachedClipMask : void 0;
34991
35239
  if (clips && !clipMask) {
@@ -34993,12 +35241,25 @@ function renderDisplayListToBitmap(displayList, options = {}) {
34993
35241
  for (const clip of clips) {
34994
35242
  const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
34995
35243
  const layer = new Uint8Array(width * height * 4);
34996
- fillEdgesScanline4x4(layer, width, height, segmentsToScreenEdges(segments, displayList.height, scale, true), { r: 1, g: 1, b: 1 }, 1, fillRule);
35244
+ fillEdgesScanline4x4(layer, width, height, pathsToEdges(segmentsToScreenPaths(segments, displayList.height, scale), true), { r: 1, g: 1, b: 1 }, 1, fillRule);
34997
35245
  for (let i = 3; i < layer.length; i += 4) clipMask[i] = Math.round(clipMask[i] * layer[i] / 255);
34998
35246
  }
34999
35247
  cachedClips = clips;
35000
35248
  cachedClipMask = clipMask;
35001
35249
  }
35250
+ const softMask = original.value.softMask;
35251
+ if (softMask) {
35252
+ if (softMask !== cachedSoftMask) {
35253
+ cachedSoftMaskPixels = renderSoftMask(softMask, displayList, scale).data;
35254
+ cachedSoftMask = softMask;
35255
+ }
35256
+ if (clipMask) {
35257
+ clipMask = clipMask.slice();
35258
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * cachedSoftMaskPixels[i] / 255);
35259
+ } else {
35260
+ clipMask = cachedSoftMaskPixels;
35261
+ }
35262
+ }
35002
35263
  const imageClips = original.value.clipImages;
35003
35264
  if (imageClips) {
35004
35265
  let imageMask = imageClipMasks.get(imageClips);
@@ -35027,62 +35288,38 @@ function renderDisplayListToBitmap(displayList, options = {}) {
35027
35288
  if (operation.kind === "path") {
35028
35289
  const path = operation.value;
35029
35290
  if (path.fillColor) {
35030
- const edges = segmentsToScreenEdges(path.segments, displayList.height, scale, true);
35291
+ const edges = pathsToEdges(segmentsToScreenPaths(path.segments, displayList.height, scale), true);
35031
35292
  const clipScreen = path.clipRect ? [path.clipRect[0] * scale, (displayList.height - path.clipRect[3]) * scale, path.clipRect[2] * scale, (displayList.height - path.clipRect[1]) * scale] : void 0;
35032
35293
  fillEdgesScanline4x4(rgba, width, height, edges, path.fillColor, path.fillAlpha ?? 1, path.fillRule ?? "nonzero", clipScreen, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
35033
35294
  }
35034
35295
  if (path.strokeColor) {
35035
- const edges = segmentsToScreenEdges(path.segments, displayList.height, scale, false);
35036
35296
  const rawSw = path.strokeWidth * scale;
35037
35297
  const sw = Math.max(1, rawSw);
35038
35298
  const strokeAlpha = options.thinLineMode === "shape" && rawSw < 1 ? (path.strokeAlpha ?? 1) * Math.max(0.25, rawSw) : path.strokeAlpha ?? 1;
35039
- const dashArr = path.dashArray && path.dashArray.length > 0 ? path.dashArray.map((d) => Math.max(0, d * scale)) : void 0;
35040
- const dashCycle = dashArr ? dashArr.reduce((a, b) => a + b, 0) : 0;
35041
- let dashDist = (path.dashPhase ?? 0) * scale % (dashCycle || 1);
35042
- if (dashDist < 0) dashDist += dashCycle;
35043
- for (const e of edges) {
35044
- if (!dashArr || dashCycle <= 1e-4) {
35045
- drawAntiAliasedSegment(rgba, width, height, e.x0, e.y0, e.x1, e.y1, sw, path.strokeColor, strokeAlpha, path.lineCap ?? 0, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
35046
- } else {
35047
- const dx = e.x1 - e.x0;
35048
- const dy = e.y1 - e.y0;
35049
- const edgeLen = Math.hypot(dx, dy);
35050
- if (edgeLen <= 1e-4) continue;
35051
- let pos = 0;
35052
- while (pos < edgeLen) {
35053
- let cycleRem = dashDist % dashCycle;
35054
- let dIdx = 0;
35055
- while (dIdx < dashArr.length - 1 && cycleRem >= dashArr[dIdx]) {
35056
- cycleRem -= dashArr[dIdx];
35057
- dIdx++;
35058
- }
35059
- const segRemainInDash = Math.max(1e-4, dashArr[dIdx] - cycleRem);
35060
- const step = Math.min(edgeLen - pos, segRemainInDash);
35061
- if (dIdx % 2 === 0) {
35062
- const t0 = pos / edgeLen;
35063
- const t1 = (pos + step) / edgeLen;
35064
- drawAntiAliasedSegment(
35065
- rgba,
35066
- width,
35067
- height,
35068
- e.x0 + dx * t0,
35069
- e.y0 + dy * t0,
35070
- e.x0 + dx * t1,
35071
- e.y0 + dy * t1,
35072
- sw,
35073
- path.strokeColor,
35074
- strokeAlpha,
35075
- path.lineCap ?? 0,
35076
- original.kind === "glyph" ? aaTxt : aaVec,
35077
- path.blendMode,
35078
- clipMask
35079
- );
35080
- }
35081
- pos += step;
35082
- dashDist = (dashDist + step) % dashCycle;
35083
- }
35084
- }
35085
- }
35299
+ const contours = strokeOutlines(
35300
+ segmentsToScreenPaths(path.segments, displayList.height, scale),
35301
+ sw,
35302
+ path.lineCap ?? 0,
35303
+ path.lineJoin ?? 0,
35304
+ path.miterLimit ?? 10,
35305
+ path.dashArray?.map((value) => Math.max(0, value * scale)),
35306
+ (path.dashPhase ?? 0) * scale
35307
+ );
35308
+ const edges = pathsToEdges(contours.map((points) => ({ points, closed: true })));
35309
+ const clipScreen = path.clipRect ? [path.clipRect[0] * scale, (displayList.height - path.clipRect[3]) * scale, path.clipRect[2] * scale, (displayList.height - path.clipRect[1]) * scale] : void 0;
35310
+ fillEdgesScanline4x4(
35311
+ rgba,
35312
+ width,
35313
+ height,
35314
+ edges,
35315
+ path.strokeColor,
35316
+ strokeAlpha,
35317
+ "nonzero",
35318
+ clipScreen,
35319
+ original.kind === "glyph" ? aaTxt : aaVec,
35320
+ path.blendMode,
35321
+ clipMask
35322
+ );
35086
35323
  }
35087
35324
  } else if (operation.kind === "image") {
35088
35325
  const img = operation.value;
@@ -37343,3 +37580,15 @@ export {
37343
37580
  * Copyright 2012 Mozilla Foundation. Licensed under Apache-2.0.
37344
37581
  * See THIRD_PARTY_NOTICES.md for the source revision and adaptations.
37345
37582
  */
37583
+ /*!
37584
+ * Anti-Grain Geometry - Version 2.3
37585
+ * Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
37586
+ *
37587
+ * Permission to copy, use, modify, sell and distribute this software
37588
+ * is granted provided this copyright notice appears in all copies.
37589
+ * This software is provided "as is" without express or implied
37590
+ * warranty, and with no claim as to its suitability for any purpose.
37591
+ *
37592
+ * Adapted from PDFium agg_math_stroke.h and agg_vcgen_stroke.cpp.
37593
+ * See THIRD_PARTY_NOTICES.md for the source revision and adaptations.
37594
+ */