@poe-platform/safe-bash 0.1.764 → 0.1.766

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.
@@ -35704,11 +35704,10 @@ function evaluateContentStreamToDisplayList(params) {
35704
35704
  } else if (operator === "d") {
35705
35705
  const arrNode = ops[0]?.kind === "array" ? ops[0] : void 0;
35706
35706
  if (arrNode) {
35707
- const ctmScale = Math.max(1e-6, Math.hypot(st.ctm[0], st.ctm[1]));
35708
- const nums = arrNode.items.map((it) => it.kind === "number" ? it.value * ctmScale : 0).filter((v) => v >= 0);
35707
+ const nums = arrNode.items.map((it) => it.kind === "number" ? it.value : 0).filter((v) => v >= 0);
35709
35708
  const sum = nums.reduce((a, b) => a + b, 0);
35710
35709
  st.dashArray = sum > 0 ? nums : void 0;
35711
- st.dashPhase = num(1, 0) * ctmScale;
35710
+ st.dashPhase = num(1, 0);
35712
35711
  } else {
35713
35712
  st.dashArray = void 0;
35714
35713
  st.dashPhase = void 0;
@@ -35840,10 +35839,11 @@ function evaluateContentStreamToDisplayList(params) {
35840
35839
  const patArr = params.cosDoc.resolveArray(dArr.items[0]);
35841
35840
  const phaseNode = params.cosDoc.resolve(dArr.items[1]);
35842
35841
  if (patArr) {
35843
- st.dashArray = patArr.items.map((it) => {
35842
+ const dashArray = patArr.items.map((it) => {
35844
35843
  const r = params.cosDoc.resolve(it);
35845
35844
  return r?.kind === "number" ? r.value : 0;
35846
- }).filter((n) => n > 0);
35845
+ }).filter((n) => n >= 0);
35846
+ st.dashArray = dashArray.some((value) => value > 0) ? dashArray : void 0;
35847
35847
  st.dashPhase = phaseNode?.kind === "number" ? phaseNode.value : 0;
35848
35848
  }
35849
35849
  }
@@ -36244,15 +36244,14 @@ function evaluateContentStreamToDisplayList(params) {
36244
36244
  break;
36245
36245
  }
36246
36246
  const fillRule = node.paint.includes("*") ? "evenodd" : "nonzero";
36247
- const ctmScale = Math.max(1e-6, Math.hypot(st.ctm[0], st.ctm[1]));
36248
- const scaledStrokeWidth = st.strokeWidth === 0 ? 0 : st.strokeWidth * ctmScale;
36249
36247
  emit({ kind: "path", value: {
36250
36248
  segments: transformedSegments,
36251
36249
  fillColor: isFill && !evaluatedFillPattern ? st.fillColor : void 0,
36252
36250
  fillAlpha: isFill && !evaluatedFillPattern ? st.fillAlpha : void 0,
36253
36251
  strokeColor: isStroke ? st.strokeColor : void 0,
36254
36252
  strokeAlpha: isStroke ? st.strokeAlpha : void 0,
36255
- strokeWidth: scaledStrokeWidth,
36253
+ strokeWidth: st.strokeWidth,
36254
+ ...isStroke ? { strokeMatrix: [...st.ctm] } : {},
36256
36255
  ...st.lineCap !== 0 ? { lineCap: st.lineCap } : {},
36257
36256
  ...st.lineJoin !== 0 ? { lineJoin: st.lineJoin } : {},
36258
36257
  ...st.miterLimit !== 10 ? { miterLimit: st.miterLimit } : {},
@@ -36440,14 +36439,14 @@ function evaluateContentStreamToDisplayList(params) {
36440
36439
  if (st.textRenderMode >= 4 && st.textRenderMode <= 7) pendingTextClip.push(...transformedGlyphSegs);
36441
36440
  const isFillGlyph = st.textRenderMode === 0 || st.textRenderMode === 2 || st.textRenderMode === 4 || st.textRenderMode === 6;
36442
36441
  const isStrokeGlyph = st.textRenderMode === 1 || st.textRenderMode === 2 || st.textRenderMode === 5 || st.textRenderMode === 6;
36443
- const ctmScale = Math.max(1e-6, Math.hypot(st.ctm[0], st.ctm[1]));
36444
36442
  const paint = {
36445
36443
  segments: transformedGlyphSegs,
36446
36444
  fillColor: isFillGlyph ? st.fillColor : void 0,
36447
36445
  fillAlpha: isFillGlyph ? st.fillAlpha : void 0,
36448
36446
  strokeColor: isStrokeGlyph ? st.strokeColor : void 0,
36449
36447
  strokeAlpha: isStrokeGlyph ? st.strokeAlpha : void 0,
36450
- strokeWidth: isStrokeGlyph ? st.strokeWidth * ctmScale : 0,
36448
+ strokeWidth: isStrokeGlyph ? st.strokeWidth : 0,
36449
+ ...isStrokeGlyph ? { strokeMatrix: [...st.ctm] } : {},
36451
36450
  fillRule: "nonzero",
36452
36451
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36453
36452
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
@@ -39412,7 +39411,7 @@ function dashSubpath(path, pattern, phase) {
39412
39411
  while (remaining <= 0) {
39413
39412
  if (++steps > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39414
39413
  if (index % 2 === 0) {
39415
- if (pattern[index] === 0) result.push({ points: [point, point], closed: false });
39414
+ if (pattern[index] === 0) result.push({ points: [point, point], closed: false, zeroLengthDash: true });
39416
39415
  flush();
39417
39416
  }
39418
39417
  index = (index + 1) % pattern.length;
@@ -39427,7 +39426,7 @@ function dashSubpath(path, pattern, phase) {
39427
39426
  throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39428
39427
  }
39429
39428
  let distance = 0;
39430
- while (distance < length) {
39429
+ while (length - distance > 8 * Number.EPSILON * Math.max(1, length)) {
39431
39430
  const point = [start[0] + dx * distance / length, start[1] + dy * distance / length];
39432
39431
  advance(point);
39433
39432
  const step = Math.min(remaining, length - distance);
@@ -39542,7 +39541,15 @@ function strokeOutlines(paths, width, cap, join, miterLimit, dashArray = [], das
39542
39541
  let closed = subpath.closed;
39543
39542
  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();
39544
39543
  if (points.length < 3) closed = false;
39545
- if (points.length === 1 && subpath.points.length > 1 && cap === 1) {
39544
+ if (points.length === 1 && cap === 2 && subpath.zeroLengthDash) {
39545
+ contour = [];
39546
+ const [x, y] = points[0];
39547
+ add(x - half, y - half);
39548
+ add(x + half, y - half);
39549
+ add(x + half, y + half);
39550
+ add(x - half, y + half);
39551
+ contours.push(contour);
39552
+ } else if (points.length === 1 && subpath.points.length > 1 && cap === 1) {
39546
39553
  contour = [];
39547
39554
  const [x, y] = points[0];
39548
39555
  addCap([x, y], [x + 1, y]);
@@ -40261,11 +40268,10 @@ function blendPixel(rgba, width, height, px, py, color, alpha, blendMode, clipMa
40261
40268
  rgba[idx + 2] = Math.round((effB * a + cbB * dstA * (1 - a)) / outA * 255);
40262
40269
  rgba[idx + 3] = Math.round(outA * 255);
40263
40270
  }
40264
- function segmentsToScreenPaths(segments, pageHeight, scale) {
40271
+ function segmentsToScreenPaths(segments, pageHeight, scale, toScreen = (x, y) => [x * scale, (pageHeight - y) * scale]) {
40265
40272
  const paths = [];
40266
40273
  let points = [];
40267
40274
  let current = [0, 0];
40268
- const toScreen = (x, y) => [x * scale, (pageHeight - y) * scale];
40269
40275
  for (const segment of segments) {
40270
40276
  if (segment.kind === "move") {
40271
40277
  if (points.length) paths.push({ points, closed: false });
@@ -40304,6 +40310,63 @@ function segmentsToScreenPaths(segments, pageHeight, scale) {
40304
40310
  if (points.length) paths.push({ points, closed: false });
40305
40311
  return paths;
40306
40312
  }
40313
+ function inverseStrokeMatrix(matrix) {
40314
+ const [a, b, c, d, e, f] = matrix;
40315
+ const det = a * d - b * c;
40316
+ if (!Number.isFinite(det) || det === 0) return void 0;
40317
+ return [d / det, -b / det, -c / det, a / det, (c * f - d * e) / det, (b * e - a * f) / det];
40318
+ }
40319
+ function prepareStroke(path, scale) {
40320
+ const matrix = path.strokeMatrix ? [...path.strokeMatrix] : [1, 0, 0, 1, 0, 0];
40321
+ const [a, b, c, d] = matrix;
40322
+ const area = Math.abs(a * d - b * c) * scale * scale;
40323
+ if (!(area > 0) || !Number.isFinite(area)) return void 0;
40324
+ const normX = Math.hypot(a, b) * scale, normY = Math.hypot(c, d) * scale;
40325
+ let width = path.strokeWidth || 1;
40326
+ const scaleX = path.strokeWidth === 0 ? normY / area : Math.max(1, normY / (width * area));
40327
+ const scaleY = path.strokeWidth === 0 ? normX / area : Math.max(1, normX / (width * area));
40328
+ let dashArray = path.dashArray, dashPhase = path.dashPhase ?? 0;
40329
+ if (scaleX === scaleY) {
40330
+ width *= scaleX;
40331
+ } else {
40332
+ matrix[0] *= scaleX;
40333
+ matrix[1] *= scaleX;
40334
+ matrix[2] *= scaleY;
40335
+ matrix[3] *= scaleY;
40336
+ if (dashArray?.length) {
40337
+ const dashScale = Math.max(scaleX, scaleY);
40338
+ dashArray = dashArray.map((value) => value / dashScale);
40339
+ dashPhase /= dashScale;
40340
+ }
40341
+ }
40342
+ return { matrix, width, dashArray, dashPhase };
40343
+ }
40344
+ function strokeContours(path, pageHeight, scale) {
40345
+ const stroke = prepareStroke(path, scale);
40346
+ if (!stroke) return [];
40347
+ const inverse = inverseStrokeMatrix(stroke.matrix);
40348
+ if (!inverse) return [];
40349
+ const [a, b, c, d, e, f] = stroke.matrix;
40350
+ const strokeScale = scale * Math.hypot(a, b, c, d);
40351
+ const project = (x, y) => [
40352
+ (inverse[0] * x + inverse[2] * y + inverse[4]) * strokeScale,
40353
+ (inverse[1] * x + inverse[3] * y + inverse[5]) * strokeScale
40354
+ ];
40355
+ const toScreen = ([x, y]) => [
40356
+ (a * x / strokeScale + c * y / strokeScale + e) * scale,
40357
+ (pageHeight - b * x / strokeScale - d * y / strokeScale - f) * scale
40358
+ ];
40359
+ const contours = strokeOutlines(
40360
+ segmentsToScreenPaths(path.segments, pageHeight, scale, project),
40361
+ stroke.width * strokeScale,
40362
+ path.lineCap ?? 0,
40363
+ path.lineJoin ?? 0,
40364
+ path.miterLimit ?? 10,
40365
+ stroke.dashArray?.map((value) => Math.max(0, value * strokeScale)),
40366
+ stroke.dashPhase * strokeScale
40367
+ );
40368
+ return contours.map((points) => points.map(toScreen));
40369
+ }
40307
40370
  function pathsToEdges(paths, closeSubpaths = false) {
40308
40371
  const edges = [];
40309
40372
  for (const { points, closed } of paths) {
@@ -40553,19 +40616,9 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40553
40616
  fillEdgesScanline4x4(rgba, width, height, edges, path.fillColor, path.fillAlpha ?? 1, path.fillRule ?? "nonzero", clipScreen, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
40554
40617
  }
40555
40618
  if (path.strokeColor) {
40556
- const rawSw = path.strokeWidth * scale;
40557
- const sw = Math.max(1, rawSw);
40619
+ const rawSw = path.strokeWidth * scale * (path.strokeMatrix ? Math.hypot(path.strokeMatrix[0], path.strokeMatrix[1]) : 1);
40558
40620
  const strokeAlpha = options.thinLineMode === "shape" && rawSw < 1 ? (path.strokeAlpha ?? 1) * Math.max(0.25, rawSw) : path.strokeAlpha ?? 1;
40559
- const contours = strokeOutlines(
40560
- segmentsToScreenPaths(path.segments, displayList.height, scale),
40561
- sw,
40562
- path.lineCap ?? 0,
40563
- path.lineJoin ?? 0,
40564
- path.miterLimit ?? 10,
40565
- path.dashArray?.map((value) => Math.max(0, value * scale)),
40566
- (path.dashPhase ?? 0) * scale
40567
- );
40568
- const edges = pathsToEdges(contours.map((points) => ({ points, closed: true })));
40621
+ const edges = pathsToEdges(strokeContours(path, displayList.height, scale).map((points) => ({ points, closed: true })));
40569
40622
  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;
40570
40623
  fillEdgesScanline4x4(
40571
40624
  rgba,
@@ -35898,11 +35898,10 @@ function evaluateContentStreamToDisplayList(params) {
35898
35898
  } else if (operator === "d") {
35899
35899
  const arrNode = ops[0]?.kind === "array" ? ops[0] : void 0;
35900
35900
  if (arrNode) {
35901
- const ctmScale = Math.max(1e-6, Math.hypot(st.ctm[0], st.ctm[1]));
35902
- const nums = arrNode.items.map((it) => it.kind === "number" ? it.value * ctmScale : 0).filter((v) => v >= 0);
35901
+ const nums = arrNode.items.map((it) => it.kind === "number" ? it.value : 0).filter((v) => v >= 0);
35903
35902
  const sum = nums.reduce((a, b) => a + b, 0);
35904
35903
  st.dashArray = sum > 0 ? nums : void 0;
35905
- st.dashPhase = num(1, 0) * ctmScale;
35904
+ st.dashPhase = num(1, 0);
35906
35905
  } else {
35907
35906
  st.dashArray = void 0;
35908
35907
  st.dashPhase = void 0;
@@ -36034,10 +36033,11 @@ function evaluateContentStreamToDisplayList(params) {
36034
36033
  const patArr = params.cosDoc.resolveArray(dArr.items[0]);
36035
36034
  const phaseNode = params.cosDoc.resolve(dArr.items[1]);
36036
36035
  if (patArr) {
36037
- st.dashArray = patArr.items.map((it) => {
36036
+ const dashArray = patArr.items.map((it) => {
36038
36037
  const r = params.cosDoc.resolve(it);
36039
36038
  return r?.kind === "number" ? r.value : 0;
36040
- }).filter((n) => n > 0);
36039
+ }).filter((n) => n >= 0);
36040
+ st.dashArray = dashArray.some((value) => value > 0) ? dashArray : void 0;
36041
36041
  st.dashPhase = phaseNode?.kind === "number" ? phaseNode.value : 0;
36042
36042
  }
36043
36043
  }
@@ -36438,15 +36438,14 @@ function evaluateContentStreamToDisplayList(params) {
36438
36438
  break;
36439
36439
  }
36440
36440
  const fillRule = node.paint.includes("*") ? "evenodd" : "nonzero";
36441
- const ctmScale = Math.max(1e-6, Math.hypot(st.ctm[0], st.ctm[1]));
36442
- const scaledStrokeWidth = st.strokeWidth === 0 ? 0 : st.strokeWidth * ctmScale;
36443
36441
  emit({ kind: "path", value: {
36444
36442
  segments: transformedSegments,
36445
36443
  fillColor: isFill && !evaluatedFillPattern ? st.fillColor : void 0,
36446
36444
  fillAlpha: isFill && !evaluatedFillPattern ? st.fillAlpha : void 0,
36447
36445
  strokeColor: isStroke ? st.strokeColor : void 0,
36448
36446
  strokeAlpha: isStroke ? st.strokeAlpha : void 0,
36449
- strokeWidth: scaledStrokeWidth,
36447
+ strokeWidth: st.strokeWidth,
36448
+ ...isStroke ? { strokeMatrix: [...st.ctm] } : {},
36450
36449
  ...st.lineCap !== 0 ? { lineCap: st.lineCap } : {},
36451
36450
  ...st.lineJoin !== 0 ? { lineJoin: st.lineJoin } : {},
36452
36451
  ...st.miterLimit !== 10 ? { miterLimit: st.miterLimit } : {},
@@ -36634,14 +36633,14 @@ function evaluateContentStreamToDisplayList(params) {
36634
36633
  if (st.textRenderMode >= 4 && st.textRenderMode <= 7) pendingTextClip.push(...transformedGlyphSegs);
36635
36634
  const isFillGlyph = st.textRenderMode === 0 || st.textRenderMode === 2 || st.textRenderMode === 4 || st.textRenderMode === 6;
36636
36635
  const isStrokeGlyph = st.textRenderMode === 1 || st.textRenderMode === 2 || st.textRenderMode === 5 || st.textRenderMode === 6;
36637
- const ctmScale = Math.max(1e-6, Math.hypot(st.ctm[0], st.ctm[1]));
36638
36636
  const paint = {
36639
36637
  segments: transformedGlyphSegs,
36640
36638
  fillColor: isFillGlyph ? st.fillColor : void 0,
36641
36639
  fillAlpha: isFillGlyph ? st.fillAlpha : void 0,
36642
36640
  strokeColor: isStrokeGlyph ? st.strokeColor : void 0,
36643
36641
  strokeAlpha: isStrokeGlyph ? st.strokeAlpha : void 0,
36644
- strokeWidth: isStrokeGlyph ? st.strokeWidth * ctmScale : 0,
36642
+ strokeWidth: isStrokeGlyph ? st.strokeWidth : 0,
36643
+ ...isStrokeGlyph ? { strokeMatrix: [...st.ctm] } : {},
36645
36644
  fillRule: "nonzero",
36646
36645
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36647
36646
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
@@ -39042,7 +39041,7 @@ function dashSubpath(path, pattern, phase) {
39042
39041
  while (remaining <= 0) {
39043
39042
  if (++steps > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39044
39043
  if (index % 2 === 0) {
39045
- if (pattern[index] === 0) result.push({ points: [point, point], closed: false });
39044
+ if (pattern[index] === 0) result.push({ points: [point, point], closed: false, zeroLengthDash: true });
39046
39045
  flush();
39047
39046
  }
39048
39047
  index = (index + 1) % pattern.length;
@@ -39057,7 +39056,7 @@ function dashSubpath(path, pattern, phase) {
39057
39056
  throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39058
39057
  }
39059
39058
  let distance = 0;
39060
- while (distance < length) {
39059
+ while (length - distance > 8 * Number.EPSILON * Math.max(1, length)) {
39061
39060
  const point = [start[0] + dx * distance / length, start[1] + dy * distance / length];
39062
39061
  advance(point);
39063
39062
  const step = Math.min(remaining, length - distance);
@@ -39172,7 +39171,15 @@ function strokeOutlines(paths, width, cap, join, miterLimit, dashArray = [], das
39172
39171
  let closed = subpath.closed;
39173
39172
  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();
39174
39173
  if (points.length < 3) closed = false;
39175
- if (points.length === 1 && subpath.points.length > 1 && cap === 1) {
39174
+ if (points.length === 1 && cap === 2 && subpath.zeroLengthDash) {
39175
+ contour = [];
39176
+ const [x, y] = points[0];
39177
+ add(x - half, y - half);
39178
+ add(x + half, y - half);
39179
+ add(x + half, y + half);
39180
+ add(x - half, y + half);
39181
+ contours.push(contour);
39182
+ } else if (points.length === 1 && subpath.points.length > 1 && cap === 1) {
39176
39183
  contour = [];
39177
39184
  const [x, y] = points[0];
39178
39185
  addCap([x, y], [x + 1, y]);
@@ -40287,11 +40294,10 @@ function blendPixel(rgba, width, height, px, py, color, alpha, blendMode, clipMa
40287
40294
  rgba[idx + 2] = Math.round((effB * a + cbB * dstA * (1 - a)) / outA * 255);
40288
40295
  rgba[idx + 3] = Math.round(outA * 255);
40289
40296
  }
40290
- function segmentsToScreenPaths(segments, pageHeight, scale) {
40297
+ function segmentsToScreenPaths(segments, pageHeight, scale, toScreen = (x, y) => [x * scale, (pageHeight - y) * scale]) {
40291
40298
  const paths = [];
40292
40299
  let points = [];
40293
40300
  let current = [0, 0];
40294
- const toScreen = (x, y) => [x * scale, (pageHeight - y) * scale];
40295
40301
  for (const segment of segments) {
40296
40302
  if (segment.kind === "move") {
40297
40303
  if (points.length) paths.push({ points, closed: false });
@@ -40330,6 +40336,63 @@ function segmentsToScreenPaths(segments, pageHeight, scale) {
40330
40336
  if (points.length) paths.push({ points, closed: false });
40331
40337
  return paths;
40332
40338
  }
40339
+ function inverseStrokeMatrix(matrix) {
40340
+ const [a, b, c, d, e, f] = matrix;
40341
+ const det = a * d - b * c;
40342
+ if (!Number.isFinite(det) || det === 0) return void 0;
40343
+ return [d / det, -b / det, -c / det, a / det, (c * f - d * e) / det, (b * e - a * f) / det];
40344
+ }
40345
+ function prepareStroke(path, scale) {
40346
+ const matrix = path.strokeMatrix ? [...path.strokeMatrix] : [1, 0, 0, 1, 0, 0];
40347
+ const [a, b, c, d] = matrix;
40348
+ const area = Math.abs(a * d - b * c) * scale * scale;
40349
+ if (!(area > 0) || !Number.isFinite(area)) return void 0;
40350
+ const normX = Math.hypot(a, b) * scale, normY = Math.hypot(c, d) * scale;
40351
+ let width = path.strokeWidth || 1;
40352
+ const scaleX = path.strokeWidth === 0 ? normY / area : Math.max(1, normY / (width * area));
40353
+ const scaleY = path.strokeWidth === 0 ? normX / area : Math.max(1, normX / (width * area));
40354
+ let dashArray = path.dashArray, dashPhase = path.dashPhase ?? 0;
40355
+ if (scaleX === scaleY) {
40356
+ width *= scaleX;
40357
+ } else {
40358
+ matrix[0] *= scaleX;
40359
+ matrix[1] *= scaleX;
40360
+ matrix[2] *= scaleY;
40361
+ matrix[3] *= scaleY;
40362
+ if (dashArray?.length) {
40363
+ const dashScale = Math.max(scaleX, scaleY);
40364
+ dashArray = dashArray.map((value) => value / dashScale);
40365
+ dashPhase /= dashScale;
40366
+ }
40367
+ }
40368
+ return { matrix, width, dashArray, dashPhase };
40369
+ }
40370
+ function strokeContours(path, pageHeight, scale) {
40371
+ const stroke = prepareStroke(path, scale);
40372
+ if (!stroke) return [];
40373
+ const inverse = inverseStrokeMatrix(stroke.matrix);
40374
+ if (!inverse) return [];
40375
+ const [a, b, c, d, e, f] = stroke.matrix;
40376
+ const strokeScale = scale * Math.hypot(a, b, c, d);
40377
+ const project = (x, y) => [
40378
+ (inverse[0] * x + inverse[2] * y + inverse[4]) * strokeScale,
40379
+ (inverse[1] * x + inverse[3] * y + inverse[5]) * strokeScale
40380
+ ];
40381
+ const toScreen = ([x, y]) => [
40382
+ (a * x / strokeScale + c * y / strokeScale + e) * scale,
40383
+ (pageHeight - b * x / strokeScale - d * y / strokeScale - f) * scale
40384
+ ];
40385
+ const contours = strokeOutlines(
40386
+ segmentsToScreenPaths(path.segments, pageHeight, scale, project),
40387
+ stroke.width * strokeScale,
40388
+ path.lineCap ?? 0,
40389
+ path.lineJoin ?? 0,
40390
+ path.miterLimit ?? 10,
40391
+ stroke.dashArray?.map((value) => Math.max(0, value * strokeScale)),
40392
+ stroke.dashPhase * strokeScale
40393
+ );
40394
+ return contours.map((points) => points.map(toScreen));
40395
+ }
40333
40396
  function pathsToEdges(paths, closeSubpaths = false) {
40334
40397
  const edges = [];
40335
40398
  for (const { points, closed } of paths) {
@@ -40579,19 +40642,9 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40579
40642
  fillEdgesScanline4x4(rgba, width, height, edges, path.fillColor, path.fillAlpha ?? 1, path.fillRule ?? "nonzero", clipScreen, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
40580
40643
  }
40581
40644
  if (path.strokeColor) {
40582
- const rawSw = path.strokeWidth * scale;
40583
- const sw = Math.max(1, rawSw);
40645
+ const rawSw = path.strokeWidth * scale * (path.strokeMatrix ? Math.hypot(path.strokeMatrix[0], path.strokeMatrix[1]) : 1);
40584
40646
  const strokeAlpha = options.thinLineMode === "shape" && rawSw < 1 ? (path.strokeAlpha ?? 1) * Math.max(0.25, rawSw) : path.strokeAlpha ?? 1;
40585
- const contours = strokeOutlines(
40586
- segmentsToScreenPaths(path.segments, displayList.height, scale),
40587
- sw,
40588
- path.lineCap ?? 0,
40589
- path.lineJoin ?? 0,
40590
- path.miterLimit ?? 10,
40591
- path.dashArray?.map((value) => Math.max(0, value * scale)),
40592
- (path.dashPhase ?? 0) * scale
40593
- );
40594
- const edges = pathsToEdges(contours.map((points) => ({ points, closed: true })));
40647
+ const edges = pathsToEdges(strokeContours(path, displayList.height, scale).map((points) => ({ points, closed: true })));
40595
40648
  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;
40596
40649
  fillEdgesScanline4x4(
40597
40650
  rgba,
@@ -40741,17 +40794,19 @@ function svgImage(image, pageHeight) {
40741
40794
  const [a, b, c, d, e, f] = image.matrix;
40742
40795
  return `<image width="1" height="1" preserveAspectRatio="none" transform="matrix(${a} ${-b} ${-c} ${d} ${e + c} ${pageHeight - f - d})" href="data:image/png;base64,${btoa(chunks.join(""))}"/>`;
40743
40796
  }
40744
- function svgPathData(segments, height) {
40797
+ function svgPathData(segments, height, matrix) {
40745
40798
  const dParts = [];
40799
+ const point = (x, y) => matrix ? `${matrix[0] * x + matrix[2] * y + matrix[4]} ${height - matrix[1] * x - matrix[3] * y - matrix[5]}` : `${x} ${height - y}`;
40746
40800
  for (const seg of segments) {
40747
40801
  if (seg.kind === "move") {
40748
- dParts.push(`M ${seg.x} ${height - seg.y}`);
40802
+ dParts.push(`M ${point(seg.x, seg.y)}`);
40749
40803
  } else if (seg.kind === "line") {
40750
- dParts.push(`L ${seg.x} ${height - seg.y}`);
40804
+ dParts.push(`L ${point(seg.x, seg.y)}`);
40751
40805
  } else if (seg.kind === "cubic") {
40752
- dParts.push(`C ${seg.x1} ${height - seg.y1} ${seg.x2} ${height - seg.y2} ${seg.x} ${height - seg.y}`);
40806
+ dParts.push(`C ${point(seg.x1, seg.y1)} ${point(seg.x2, seg.y2)} ${point(seg.x, seg.y)}`);
40753
40807
  } else if (seg.kind === "rect") {
40754
- dParts.push(`M ${seg.x} ${height - seg.y} h ${seg.width} v ${-seg.height} h ${-seg.width} Z`);
40808
+ if (matrix) dParts.push(`M ${point(seg.x, seg.y)} L ${point(seg.x + seg.width, seg.y)} L ${point(seg.x + seg.width, seg.y + seg.height)} L ${point(seg.x, seg.y + seg.height)} Z`);
40809
+ else dParts.push(`M ${seg.x} ${height - seg.y} h ${seg.width} v ${-seg.height} h ${-seg.width} Z`);
40755
40810
  } else if (seg.kind === "close") {
40756
40811
  dParts.push("Z");
40757
40812
  }
@@ -40830,21 +40885,34 @@ function renderDisplayListToSvg(displayList, options = {}) {
40830
40885
  parts.push("</g>");
40831
40886
  } else if (operation.kind === "path") {
40832
40887
  const p = operation.value;
40833
- const pathData = svgPathData(p.segments, displayList.height);
40888
+ const prepared = p.strokeColor ? prepareStroke(p, Math.max(scaleX, scaleY)) : void 0;
40889
+ const outlineStroke = prepared && p.dashArray?.includes(0);
40890
+ const matrix = prepared && (prepared.matrix[0] !== 1 || prepared.matrix[1] !== 0 || prepared.matrix[2] !== 0 || prepared.matrix[3] !== 1) ? prepared.matrix : void 0;
40891
+ const inverse = matrix ? inverseStrokeMatrix(matrix) : void 0;
40892
+ const pathData = svgPathData(p.segments, inverse ? 0 : displayList.height, inverse);
40893
+ const transformAttr = inverse && matrix ? ` transform="matrix(${matrix[0]} ${-matrix[1]} ${-matrix[2]} ${matrix[3]} ${matrix[4]} ${displayList.height - matrix[5]})"` : "";
40834
40894
  if (pathData) {
40835
40895
  const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
40836
- const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
40896
+ const stroke = p.strokeColor && prepared ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
40837
40897
  const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
40838
40898
  const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
40839
40899
  const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
40840
- const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
40900
+ const strokeWidthAttr = p.strokeWidth <= 0 && !matrix && !p.dashArray?.length ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${prepared?.width ?? p.strokeWidth}"`;
40841
40901
  const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
40842
40902
  const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
40843
40903
  const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
40844
- const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
40845
- const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
40904
+ const dashArrayAttr = !outlineStroke && prepared?.dashArray?.length ? ` stroke-dasharray="${prepared.dashArray.join(" ")}"` : "";
40905
+ const dashOffsetAttr = !outlineStroke && prepared?.dashPhase ? ` stroke-dashoffset="${prepared.dashPhase}"` : "";
40846
40906
  const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
40847
- parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
40907
+ if (!outlineStroke || p.fillColor) {
40908
+ parts.push(` <path${labelAttr}${transformAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${outlineStroke ? "none" : stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
40909
+ }
40910
+ if (outlineStroke) {
40911
+ const outlineScale = Math.max(scaleX, scaleY);
40912
+ const contours = strokeContours(p, displayList.height, outlineScale);
40913
+ const outlineData = contours.map((points) => points.map(([x, y], i) => `${i === 0 ? "M" : "L"} ${x / outlineScale} ${y / outlineScale}`).join(" ") + " Z").join(" ");
40914
+ if (outlineData) parts.push(` <path${labelAttr} d="${outlineData}" fill="${stroke}" fill-opacity="${p.strokeAlpha ?? 1}"/>`);
40915
+ }
40848
40916
  }
40849
40917
  } else if (operation.kind === "image") {
40850
40918
  parts.push(` ${svgImage(operation.value, displayList.height)}`);
@@ -36049,11 +36049,10 @@ function evaluateContentStreamToDisplayList(params) {
36049
36049
  } else if (operator === "d") {
36050
36050
  const arrNode = ops[0]?.kind === "array" ? ops[0] : void 0;
36051
36051
  if (arrNode) {
36052
- const ctmScale = Math.max(1e-6, Math.hypot(st.ctm[0], st.ctm[1]));
36053
- const nums = arrNode.items.map((it) => it.kind === "number" ? it.value * ctmScale : 0).filter((v) => v >= 0);
36052
+ const nums = arrNode.items.map((it) => it.kind === "number" ? it.value : 0).filter((v) => v >= 0);
36054
36053
  const sum = nums.reduce((a, b) => a + b, 0);
36055
36054
  st.dashArray = sum > 0 ? nums : void 0;
36056
- st.dashPhase = num(1, 0) * ctmScale;
36055
+ st.dashPhase = num(1, 0);
36057
36056
  } else {
36058
36057
  st.dashArray = void 0;
36059
36058
  st.dashPhase = void 0;
@@ -36185,10 +36184,11 @@ function evaluateContentStreamToDisplayList(params) {
36185
36184
  const patArr = params.cosDoc.resolveArray(dArr.items[0]);
36186
36185
  const phaseNode = params.cosDoc.resolve(dArr.items[1]);
36187
36186
  if (patArr) {
36188
- st.dashArray = patArr.items.map((it) => {
36187
+ const dashArray = patArr.items.map((it) => {
36189
36188
  const r = params.cosDoc.resolve(it);
36190
36189
  return r?.kind === "number" ? r.value : 0;
36191
- }).filter((n) => n > 0);
36190
+ }).filter((n) => n >= 0);
36191
+ st.dashArray = dashArray.some((value) => value > 0) ? dashArray : void 0;
36192
36192
  st.dashPhase = phaseNode?.kind === "number" ? phaseNode.value : 0;
36193
36193
  }
36194
36194
  }
@@ -36589,15 +36589,14 @@ function evaluateContentStreamToDisplayList(params) {
36589
36589
  break;
36590
36590
  }
36591
36591
  const fillRule = node.paint.includes("*") ? "evenodd" : "nonzero";
36592
- const ctmScale = Math.max(1e-6, Math.hypot(st.ctm[0], st.ctm[1]));
36593
- const scaledStrokeWidth = st.strokeWidth === 0 ? 0 : st.strokeWidth * ctmScale;
36594
36592
  emit({ kind: "path", value: {
36595
36593
  segments: transformedSegments,
36596
36594
  fillColor: isFill && !evaluatedFillPattern ? st.fillColor : void 0,
36597
36595
  fillAlpha: isFill && !evaluatedFillPattern ? st.fillAlpha : void 0,
36598
36596
  strokeColor: isStroke ? st.strokeColor : void 0,
36599
36597
  strokeAlpha: isStroke ? st.strokeAlpha : void 0,
36600
- strokeWidth: scaledStrokeWidth,
36598
+ strokeWidth: st.strokeWidth,
36599
+ ...isStroke ? { strokeMatrix: [...st.ctm] } : {},
36601
36600
  ...st.lineCap !== 0 ? { lineCap: st.lineCap } : {},
36602
36601
  ...st.lineJoin !== 0 ? { lineJoin: st.lineJoin } : {},
36603
36602
  ...st.miterLimit !== 10 ? { miterLimit: st.miterLimit } : {},
@@ -36785,14 +36784,14 @@ function evaluateContentStreamToDisplayList(params) {
36785
36784
  if (st.textRenderMode >= 4 && st.textRenderMode <= 7) pendingTextClip.push(...transformedGlyphSegs);
36786
36785
  const isFillGlyph = st.textRenderMode === 0 || st.textRenderMode === 2 || st.textRenderMode === 4 || st.textRenderMode === 6;
36787
36786
  const isStrokeGlyph = st.textRenderMode === 1 || st.textRenderMode === 2 || st.textRenderMode === 5 || st.textRenderMode === 6;
36788
- const ctmScale = Math.max(1e-6, Math.hypot(st.ctm[0], st.ctm[1]));
36789
36787
  const paint = {
36790
36788
  segments: transformedGlyphSegs,
36791
36789
  fillColor: isFillGlyph ? st.fillColor : void 0,
36792
36790
  fillAlpha: isFillGlyph ? st.fillAlpha : void 0,
36793
36791
  strokeColor: isStrokeGlyph ? st.strokeColor : void 0,
36794
36792
  strokeAlpha: isStrokeGlyph ? st.strokeAlpha : void 0,
36795
- strokeWidth: isStrokeGlyph ? st.strokeWidth * ctmScale : 0,
36793
+ strokeWidth: isStrokeGlyph ? st.strokeWidth : 0,
36794
+ ...isStrokeGlyph ? { strokeMatrix: [...st.ctm] } : {},
36796
36795
  fillRule: "nonzero",
36797
36796
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36798
36797
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
@@ -39193,7 +39192,7 @@ function dashSubpath(path, pattern, phase) {
39193
39192
  while (remaining <= 0) {
39194
39193
  if (++steps > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39195
39194
  if (index % 2 === 0) {
39196
- if (pattern[index] === 0) result.push({ points: [point, point], closed: false });
39195
+ if (pattern[index] === 0) result.push({ points: [point, point], closed: false, zeroLengthDash: true });
39197
39196
  flush();
39198
39197
  }
39199
39198
  index = (index + 1) % pattern.length;
@@ -39208,7 +39207,7 @@ function dashSubpath(path, pattern, phase) {
39208
39207
  throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39209
39208
  }
39210
39209
  let distance = 0;
39211
- while (distance < length) {
39210
+ while (length - distance > 8 * Number.EPSILON * Math.max(1, length)) {
39212
39211
  const point = [start[0] + dx * distance / length, start[1] + dy * distance / length];
39213
39212
  advance(point);
39214
39213
  const step = Math.min(remaining, length - distance);
@@ -39323,7 +39322,15 @@ function strokeOutlines(paths, width, cap, join, miterLimit, dashArray = [], das
39323
39322
  let closed = subpath.closed;
39324
39323
  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();
39325
39324
  if (points.length < 3) closed = false;
39326
- if (points.length === 1 && subpath.points.length > 1 && cap === 1) {
39325
+ if (points.length === 1 && cap === 2 && subpath.zeroLengthDash) {
39326
+ contour = [];
39327
+ const [x, y] = points[0];
39328
+ add(x - half, y - half);
39329
+ add(x + half, y - half);
39330
+ add(x + half, y + half);
39331
+ add(x - half, y + half);
39332
+ contours.push(contour);
39333
+ } else if (points.length === 1 && subpath.points.length > 1 && cap === 1) {
39327
39334
  contour = [];
39328
39335
  const [x, y] = points[0];
39329
39336
  addCap([x, y], [x + 1, y]);
@@ -40269,11 +40276,10 @@ function blendPixel(rgba, width, height, px, py, color, alpha, blendMode, clipMa
40269
40276
  rgba[idx + 2] = Math.round((effB * a + cbB * dstA * (1 - a)) / outA * 255);
40270
40277
  rgba[idx + 3] = Math.round(outA * 255);
40271
40278
  }
40272
- function segmentsToScreenPaths(segments, pageHeight, scale) {
40279
+ function segmentsToScreenPaths(segments, pageHeight, scale, toScreen = (x, y) => [x * scale, (pageHeight - y) * scale]) {
40273
40280
  const paths = [];
40274
40281
  let points = [];
40275
40282
  let current = [0, 0];
40276
- const toScreen = (x, y) => [x * scale, (pageHeight - y) * scale];
40277
40283
  for (const segment of segments) {
40278
40284
  if (segment.kind === "move") {
40279
40285
  if (points.length) paths.push({ points, closed: false });
@@ -40312,6 +40318,63 @@ function segmentsToScreenPaths(segments, pageHeight, scale) {
40312
40318
  if (points.length) paths.push({ points, closed: false });
40313
40319
  return paths;
40314
40320
  }
40321
+ function inverseStrokeMatrix(matrix) {
40322
+ const [a, b, c, d, e, f] = matrix;
40323
+ const det = a * d - b * c;
40324
+ if (!Number.isFinite(det) || det === 0) return void 0;
40325
+ return [d / det, -b / det, -c / det, a / det, (c * f - d * e) / det, (b * e - a * f) / det];
40326
+ }
40327
+ function prepareStroke(path, scale) {
40328
+ const matrix = path.strokeMatrix ? [...path.strokeMatrix] : [1, 0, 0, 1, 0, 0];
40329
+ const [a, b, c, d] = matrix;
40330
+ const area = Math.abs(a * d - b * c) * scale * scale;
40331
+ if (!(area > 0) || !Number.isFinite(area)) return void 0;
40332
+ const normX = Math.hypot(a, b) * scale, normY = Math.hypot(c, d) * scale;
40333
+ let width = path.strokeWidth || 1;
40334
+ const scaleX = path.strokeWidth === 0 ? normY / area : Math.max(1, normY / (width * area));
40335
+ const scaleY = path.strokeWidth === 0 ? normX / area : Math.max(1, normX / (width * area));
40336
+ let dashArray = path.dashArray, dashPhase = path.dashPhase ?? 0;
40337
+ if (scaleX === scaleY) {
40338
+ width *= scaleX;
40339
+ } else {
40340
+ matrix[0] *= scaleX;
40341
+ matrix[1] *= scaleX;
40342
+ matrix[2] *= scaleY;
40343
+ matrix[3] *= scaleY;
40344
+ if (dashArray?.length) {
40345
+ const dashScale = Math.max(scaleX, scaleY);
40346
+ dashArray = dashArray.map((value) => value / dashScale);
40347
+ dashPhase /= dashScale;
40348
+ }
40349
+ }
40350
+ return { matrix, width, dashArray, dashPhase };
40351
+ }
40352
+ function strokeContours(path, pageHeight, scale) {
40353
+ const stroke = prepareStroke(path, scale);
40354
+ if (!stroke) return [];
40355
+ const inverse = inverseStrokeMatrix(stroke.matrix);
40356
+ if (!inverse) return [];
40357
+ const [a, b, c, d, e, f] = stroke.matrix;
40358
+ const strokeScale = scale * Math.hypot(a, b, c, d);
40359
+ const project = (x, y) => [
40360
+ (inverse[0] * x + inverse[2] * y + inverse[4]) * strokeScale,
40361
+ (inverse[1] * x + inverse[3] * y + inverse[5]) * strokeScale
40362
+ ];
40363
+ const toScreen = ([x, y]) => [
40364
+ (a * x / strokeScale + c * y / strokeScale + e) * scale,
40365
+ (pageHeight - b * x / strokeScale - d * y / strokeScale - f) * scale
40366
+ ];
40367
+ const contours = strokeOutlines(
40368
+ segmentsToScreenPaths(path.segments, pageHeight, scale, project),
40369
+ stroke.width * strokeScale,
40370
+ path.lineCap ?? 0,
40371
+ path.lineJoin ?? 0,
40372
+ path.miterLimit ?? 10,
40373
+ stroke.dashArray?.map((value) => Math.max(0, value * strokeScale)),
40374
+ stroke.dashPhase * strokeScale
40375
+ );
40376
+ return contours.map((points) => points.map(toScreen));
40377
+ }
40315
40378
  function pathsToEdges(paths, closeSubpaths = false) {
40316
40379
  const edges = [];
40317
40380
  for (const { points, closed } of paths) {
@@ -40561,19 +40624,9 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40561
40624
  fillEdgesScanline4x4(rgba, width, height, edges, path.fillColor, path.fillAlpha ?? 1, path.fillRule ?? "nonzero", clipScreen, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
40562
40625
  }
40563
40626
  if (path.strokeColor) {
40564
- const rawSw = path.strokeWidth * scale;
40565
- const sw = Math.max(1, rawSw);
40627
+ const rawSw = path.strokeWidth * scale * (path.strokeMatrix ? Math.hypot(path.strokeMatrix[0], path.strokeMatrix[1]) : 1);
40566
40628
  const strokeAlpha = options.thinLineMode === "shape" && rawSw < 1 ? (path.strokeAlpha ?? 1) * Math.max(0.25, rawSw) : path.strokeAlpha ?? 1;
40567
- const contours = strokeOutlines(
40568
- segmentsToScreenPaths(path.segments, displayList.height, scale),
40569
- sw,
40570
- path.lineCap ?? 0,
40571
- path.lineJoin ?? 0,
40572
- path.miterLimit ?? 10,
40573
- path.dashArray?.map((value) => Math.max(0, value * scale)),
40574
- (path.dashPhase ?? 0) * scale
40575
- );
40576
- const edges = pathsToEdges(contours.map((points) => ({ points, closed: true })));
40629
+ const edges = pathsToEdges(strokeContours(path, displayList.height, scale).map((points) => ({ points, closed: true })));
40577
40630
  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;
40578
40631
  fillEdgesScanline4x4(
40579
40632
  rgba,