emf-converter 4.8.20 → 4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11662,11 +11662,20 @@ function ellipseBeziersBox(box, clockwise = false) {
11662
11662
  if (!clockwise) {
11663
11663
  return ellipsePoints(box, false);
11664
11664
  }
11665
- const e = clockwiseEllipseBeziersBox(box);
11665
+ const { halfX, ...plain } = box;
11666
+ const e = clockwiseEllipseBeziersBox(plain);
11666
11667
  const out = [];
11667
11668
  for (let i = e.length - 2; i >= 0; i -= 2) {
11668
11669
  out.push(e[i], e[i + 1]);
11669
11670
  }
11671
+ const odd = Math.abs(plain.exx) % 2;
11672
+ out[18] += odd;
11673
+ out[6] -= odd;
11674
+ if (halfX) {
11675
+ for (const k of [0, 1, 2, 3, 4, 5, 12]) {
11676
+ out[2 * k]++;
11677
+ }
11678
+ }
11670
11679
  return out;
11671
11680
  }
11672
11681
  function clockwiseEllipseBeziersBox(box) {
@@ -11682,10 +11691,10 @@ function ellipsePoints(box, cwControls) {
11682
11691
  const vMidHi = (v) => half(v, true);
11683
11692
  const vCtl = (v) => Math.floor(v / 2) - Math.floor(KAPPA * Math.floor(v / 2));
11684
11693
  const vCtlR = (v) => v - vCtl(v);
11685
- const vDist = (v) => Math.ceil(KAPPA * Math.floor(v / 2));
11686
- const rightUpper = cwControls ? (v) => vMidHi(v) - vDist(v) : vCtl;
11694
+ const vDist = (v) => v % 2 === 0 ? Math.ceil(KAPPA * Math.floor(v / 2)) : Math.floor(KAPPA * Math.ceil(v / 2));
11695
+ const rightUpper = cwControls ? (v) => vMidLo(v) - vDist(v) : vCtl;
11687
11696
  const leftUpper = cwControls ? (v) => vMidLo(v) - vDist(v) : vCtl;
11688
- const leftLower = cwControls ? (v) => vMidLo(v) + vDist(v) : vCtlR;
11697
+ const leftLower = cwControls ? (v) => vMidHi(v) + vDist(v) : vCtlR;
11689
11698
  const rightLower = cwControls ? (v) => vMidHi(v) + vDist(v) : vCtlR;
11690
11699
  const zero = () => 0;
11691
11700
  const full = (v) => v;
@@ -11927,7 +11936,7 @@ function unitPiece(from, to, small) {
11927
11936
  }
11928
11937
  return { start: p0, ctrl };
11929
11938
  }
11930
- function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise) {
11939
+ function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise, halfX = false, framed = false) {
11931
11940
  const w = r - l;
11932
11941
  const h = b - t;
11933
11942
  const Q = Math.PI / 2;
@@ -11947,11 +11956,25 @@ function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise) {
11947
11956
  } else {
11948
11957
  while (a1 >= a0) a1 -= 2 * Math.PI;
11949
11958
  }
11950
- const px = (u) => Math.round(cx + rx * u);
11959
+ const px = (u, v) => clockwise && halfX ? Math.ceil(cx + rx * u + 0.5 - v) : Math.round(cx + rx * u + (halfX ? 1 + v : 0));
11951
11960
  const py = (v) => Math.round(cy - ry * v);
11952
- const E = clockwise ? clockwiseEllipseBeziersBox(axisBox(l, t, r, b)) : ellipseBeziers(l, t, r, b);
11961
+ const eb = axisBox(l, t, r, b);
11962
+ if (halfX) eb.halfX = true;
11963
+ const E = ellipseBeziersBox(eb);
11964
+ if (clockwise) {
11965
+ const cwPts = ellipseBeziersBox(eb, true);
11966
+ for (let i = 0; i < cwPts.length; i += 2) {
11967
+ E[cwPts.length - 2 - i] = cwPts[i];
11968
+ E[cwPts.length - 1 - i] = cwPts[i + 1];
11969
+ }
11970
+ }
11953
11971
  const startUnit = small ? [Math.cos(a0), Math.sin(a0)] : polygonTrig(a0);
11954
- const out = [px(startUnit[0]), py(startUnit[1])];
11972
+ const out = [px(startUnit[0], startUnit[1]), py(startUnit[1])];
11973
+ const onAxis = (angle2) => Math.abs(angle2 / Q - Math.round(angle2 / Q)) < 1e-9;
11974
+ const axisQuadrant = (angle2) => (Math.round(angle2 / Q) % 4 + 4) % 4;
11975
+ if (framed && onAxis(a0) && (s > 0 ? axisQuadrant(a0) === 1 || axisQuadrant(a0) === 2 : axisQuadrant(a0) === 2 || axisQuadrant(a0) === 3)) {
11976
+ out.push(out[0], out[1], out[0], out[1], out[0], out[1]);
11977
+ }
11955
11978
  let a = a0;
11956
11979
  for (let guard = 0; guard < 8 && (s > 0 ? a < a1 - 1e-12 : a > a1 + 1e-12); guard++) {
11957
11980
  const next = s > 0 ? Math.floor(a / Q + 1e-9) * Q + Q : Math.ceil(a / Q - 1e-9) * Q - Q;
@@ -11973,10 +11996,16 @@ function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise) {
11973
11996
  const e = s > 0 ? Math.min(next, a1) : Math.max(next, a1);
11974
11997
  const piece = unitPiece(a, e, small);
11975
11998
  for (let i = 0; i < 6; i += 2) {
11976
- out.push(px(piece.ctrl[i]), py(piece.ctrl[i + 1]));
11999
+ out.push(px(piece.ctrl[i], piece.ctrl[i + 1]), py(piece.ctrl[i + 1]));
11977
12000
  }
11978
12001
  a = e;
11979
12002
  }
12003
+ if (framed && onAxis(a1) && (s > 0 ? axisQuadrant(a1) === 3 || axisQuadrant(a1) === 0 : axisQuadrant(a1) === 1 || axisQuadrant(a1) === 0)) {
12004
+ const endUnit = polygonTrig(a1);
12005
+ const ex = px(endUnit[0], endUnit[1]);
12006
+ const ey = py(endUnit[1]);
12007
+ out.push(ex, ey, ex, ey, ex, ey);
12008
+ }
11980
12009
  return out;
11981
12010
  }
11982
12011
  var GdiRasterPath = class {
@@ -29615,7 +29644,7 @@ var Outliner = class {
29615
29644
  this.flush();
29616
29645
  }
29617
29646
  };
29618
- function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors) {
29647
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric) {
29619
29648
  const out = [];
29620
29649
  const dashes = [];
29621
29650
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29635,8 +29664,8 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29635
29664
  const [x0, y0] = P[i];
29636
29665
  const [x1, y1] = P[i + 1];
29637
29666
  const dir = [x1 - x0, y1 - y0];
29638
- const real = Math.hypot(dir[0], dir[1]);
29639
- const len = wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29667
+ const real = metric ? Math.hypot(dir[0] / metric[0], dir[1] / metric[1]) : Math.hypot(dir[0], dir[1]);
29668
+ const len = metric ? real : wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29640
29669
  if (len === 0) {
29641
29670
  if (on && cur) {
29642
29671
  cur.pts.push(P[i + 1]);
@@ -29709,10 +29738,10 @@ function widenPath(path, opts) {
29709
29738
  }
29710
29739
  if (dashed) {
29711
29740
  const run = closed ? [...P, P[0]] : P;
29712
- const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.width;
29741
+ const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.dashMetric ? opts.width / opts.dashMetric[0] : opts.width;
29713
29742
  const runTangents = closed ? [...dirs, void 0] : dirs;
29714
29743
  const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29715
- for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors)) {
29744
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric)) {
29716
29745
  const pts = [piece.pts[0]];
29717
29746
  const pdirs = [];
29718
29747
  const pdraws = [];
@@ -29794,6 +29823,10 @@ function flipBox(box) {
29794
29823
  }
29795
29824
  function rectRasterPath(box, clockwise = false) {
29796
29825
  const c = boxCorners(clockwise ? flipBox(box) : box);
29826
+ if (box.halfXRect) {
29827
+ c[4]--;
29828
+ c[6]--;
29829
+ }
29797
29830
  const path = new GdiRasterPath();
29798
29831
  path.moveTo(c[0], c[1]);
29799
29832
  path.lineTo(c[2], c[3]);
@@ -29840,8 +29873,49 @@ function roundRectDeviceBeziers(box, cw, ch, clockwise = false, compatible = fal
29840
29873
  pts.push(...map(q[i], clockwise ? f.t + f.b - q[i + 1] : q[i + 1]));
29841
29874
  }
29842
29875
  if (box.halfX) {
29843
- for (const k of [1, 2, 3, 4, 5, 6, 8, 15]) {
29844
- pts[2 * k]++;
29876
+ if (box.halfXCompat || !clockwise) {
29877
+ const cy = (f.t + f.b) / 2;
29878
+ const ry = (f.b - f.t) / 2 || 1;
29879
+ for (let k = 0; k < 16; k++) {
29880
+ const v = (cy - pts[2 * k + 1]) / ry;
29881
+ pts[2 * k] += k >= 8 ? Math.round(1 + v) : Math.ceil(v - 0.5);
29882
+ }
29883
+ } else {
29884
+ const tall = box.cornerExact !== void 0 && box.cornerExact[1] * 2 >= Math.abs(box.eyy) - 1e-9;
29885
+ for (const k of tall ? [1, 2, 3, 4, 5, 6, 8, 15] : [0, 1, 2, 3, 4, 5, 6, 7]) {
29886
+ pts[2 * k]++;
29887
+ }
29888
+ }
29889
+ }
29890
+ if (box.cornerExact && isAxisBox(box)) {
29891
+ const w = f.r - f.l;
29892
+ const h = f.b - f.t;
29893
+ if (w >= 0 && h >= 0) {
29894
+ const hx = w === 0 ? 0 : Math.round(box.cornerExact[0] * (w + w % 2) / w / 2);
29895
+ const hy = h === 0 ? 0 : Math.round(box.cornerExact[1] * (clockwise ? h + h % 2 : h - h % 2) / h / 2);
29896
+ const hc = Math.ceil(KAPPA * hx);
29897
+ const vc = clockwise ? Math.ceil(KAPPA * hy) : Math.floor(KAPPA * hy);
29898
+ const set = (k, x, y) => {
29899
+ if (x !== null) pts[2 * k] = x;
29900
+ pts[2 * k + 1] = clockwise ? f.t + f.b - y : y;
29901
+ };
29902
+ const a = box.halfX ? 1 : 0;
29903
+ set(0, null, f.t + hy);
29904
+ set(1, null, f.t + hy - vc);
29905
+ set(2, f.r + a - hx + hc, f.t);
29906
+ set(3, f.r + a - hx, f.t);
29907
+ set(4, f.l + a + hx, f.t);
29908
+ set(5, f.l + a + hx - hc, f.t);
29909
+ set(6, null, f.t + hy - vc);
29910
+ set(7, null, f.t + hy);
29911
+ set(8, null, f.b - hy);
29912
+ set(9, null, f.b - hy + vc);
29913
+ set(10, f.l + hx - hc, f.b);
29914
+ set(11, f.l + hx, f.b);
29915
+ set(12, f.r - hx, f.b);
29916
+ set(13, f.r - hx + hc, f.b);
29917
+ set(14, null, f.b - hy + vc);
29918
+ set(15, null, f.b - hy);
29845
29919
  }
29846
29920
  }
29847
29921
  return pts;
@@ -29884,7 +29958,7 @@ function arcRasterPath(box, s, e, clockwise, kind, from, path = new GdiRasterPat
29884
29958
  cw = !cw;
29885
29959
  }
29886
29960
  }
29887
- const bz = arcBeziers(f.l, f.t, f.r, f.b, sx, sy, ex, ey, cw);
29961
+ const bz = arcBeziers(f.l, f.t, f.r, f.b, sx, sy, ex, ey, cw, !!box.halfX, !!box.framed);
29888
29962
  const pts = [];
29889
29963
  for (let i = 0; i < bz.length; i += 2) {
29890
29964
  pts.push(...map(bz[i], bz[i + 1]));
@@ -29898,7 +29972,7 @@ function arcRasterPath(box, s, e, clockwise, kind, from, path = new GdiRasterPat
29898
29972
  if (kind === "pie") {
29899
29973
  const w = f.r - f.l;
29900
29974
  const h = f.b - f.t;
29901
- const [cx, cy] = map(f.l + Math.ceil(w / 2), f.t + Math.ceil(h / 2));
29975
+ const [cx, cy] = map(f.l + Math.ceil(w / 2) + (box.halfX ? 1 : 0), f.t + Math.ceil(h / 2));
29902
29976
  path.lineTo(cx, cy);
29903
29977
  }
29904
29978
  if (kind === "pie" || kind === "chord") {
@@ -29934,8 +30008,9 @@ function penWidenOptions(rCtx, opts = {}) {
29934
30008
  const widthPx = rCtx.wholeDevicePixels && (flags & 15) === 6 ? state.penWidth * Math.sqrt(Math.abs(matrix[0] * matrix[3] - matrix[1] * matrix[2])) : penDeviceWidth(rCtx);
29935
30009
  const capBits = flags & 3840;
29936
30010
  const joinBits = flags & 61440;
29937
- const dashes = state.penExtended ? geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
29938
- const ellipse = !dashes && !rCtx.wholeDevicePixels && state.penWidth * Math.abs(matrix[0]) * 16 >= 1 && state.penWidth * Math.abs(matrix[3]) * 16 >= 1 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6 && Math.abs(Math.abs(matrix[0]) - Math.abs(matrix[3])) > 1e-6;
30011
+ const ellipse = !rCtx.wholeDevicePixels && state.penWidth * Math.abs(matrix[0]) * 16 >= 1 && state.penWidth * Math.abs(matrix[3]) * 16 >= 1 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6 && Math.abs(Math.abs(matrix[0]) - Math.abs(matrix[3])) > 1e-6;
30012
+ const dashes = state.penExtended ? ellipse ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30013
+ const dashMetric = ellipse && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
29939
30014
  return {
29940
30015
  width: Math.round((ellipse ? state.penWidth * Math.abs(matrix[0]) : widthPx) * 16),
29941
30016
  ...ellipse ? { height: Math.round(state.penWidth * Math.abs(matrix[3]) * 16) } : {},
@@ -29943,6 +30018,7 @@ function penWidenOptions(rCtx, opts = {}) {
29943
30018
  join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
29944
30019
  miterLimit: state.miterLimit ?? 10,
29945
30020
  dashes: dashes ? dashes.map((v) => v * 16) : null,
30021
+ ...dashMetric ? { dashMetric } : {},
29946
30022
  shortenDashes: (flags & 15) !== 7,
29947
30023
  // One logical unit per device pixel, unrotated: GDI measures dash
29948
30024
  // segments in whole pixels.
@@ -30955,9 +31031,24 @@ function insideFrameInset(rCtx, box, rectangle = false, clockwiseRoundRect = fal
30955
31031
  right: Math.round((rectangle ? lo : hi) * px),
30956
31032
  top: y,
30957
31033
  bottom: y,
30958
- half: wx % 2 === 1 && !rectangle
31034
+ half: wx % 2 === 1 && !rectangle,
31035
+ halfRect: wx % 2 === 1 && rectangle
30959
31036
  };
30960
31037
  }
31038
+ function insideFramePenTooWide(rCtx, box) {
31039
+ if ((rCtx.state.penStyle & 15) !== PS_INSIDEFRAME || !isAxisBox(box) || hasWorldRotation(rCtx)) {
31040
+ return false;
31041
+ }
31042
+ const m = gdiDeviceMatrix(rCtx);
31043
+ const px = gdiDevicePixelX(rCtx);
31044
+ const py = gdiDevicePixelY(rCtx);
31045
+ const widthX = Math.abs(rCtx.state.penWidth * m[0]) / px * 16;
31046
+ const widthY = Math.abs(rCtx.state.penWidth * m[3]) / py * 16;
31047
+ if (Math.max(widthX, widthY) < 24) {
31048
+ return false;
31049
+ }
31050
+ return Math.abs(box.exx) / px < Math.round(widthX) || Math.abs(box.eyy) / py < Math.round(widthY);
31051
+ }
30961
31052
  function insetFixBox(box, inset) {
30962
31053
  const sx = box.exx < 0 ? -1 : 1;
30963
31054
  const sy = box.eyy < 0 ? -1 : 1;
@@ -30967,11 +31058,15 @@ function insetFixBox(box, inset) {
30967
31058
  exx: box.exx - sx * (inset.left + inset.right),
30968
31059
  exy: 0,
30969
31060
  eyx: 0,
30970
- eyy: box.eyy - sy * (inset.top + inset.bottom)
31061
+ eyy: box.eyy - sy * (inset.top + inset.bottom),
31062
+ framed: true
30971
31063
  };
30972
31064
  if (inset.half && sx > 0) {
30973
31065
  framed.halfX = true;
30974
31066
  }
31067
+ if (inset.halfRect && sx > 0) {
31068
+ framed.halfXRect = true;
31069
+ }
30975
31070
  return framed;
30976
31071
  }
30977
31072
  function sameEllipseRay(l, t, r, b, sx, sy, ex, ey) {
@@ -31054,7 +31149,7 @@ function handleRectangle(rCtx, dataOff, recSize) {
31054
31149
  const r = view.getInt32(dataOff + 8, true);
31055
31150
  const b = view.getInt32(dataOff + 12, true);
31056
31151
  const unframed = uprightFixBox(rCtx, l, t, r, b);
31057
- const inset = insideFrameInset(rCtx, unframed, true);
31152
+ const inset = insideFrameInset(rCtx, unframed, true, rCtx.state.arcDirection === 2);
31058
31153
  const box = inset ? insetFixBox(unframed, inset) : unframed;
31059
31154
  const clockwise = rCtx.state.arcDirection === 2;
31060
31155
  if (!inPath) {
@@ -31240,6 +31335,13 @@ function handleRoundRect(rCtx, dataOff, recSize) {
31240
31335
  gmh(rCtx, cornerH) / 2,
31241
31336
  null
31242
31337
  );
31338
+ if (inset) {
31339
+ const fullW = Math.abs((r - l) * devM[0]) * 16;
31340
+ const fullH = Math.abs((b - t) * devM[3]) * 16;
31341
+ if (fullW > 0 && fullH > 0) {
31342
+ framed.cornerExact = [Math.min(cornerFixW, fullW) * Math.abs(framed.exx) / fullW, Math.min(cornerFixH, fullH) * Math.abs(framed.eyy) / fullH];
31343
+ }
31344
+ }
31243
31345
  const raster = (box = framed) => roundRectRasterPath(box, cw, ch, clockwise, cornerW === 0 || cornerH === 0);
31244
31346
  if (inPath) {
31245
31347
  const box = framed;
@@ -31293,7 +31395,7 @@ function handleEllipse(rCtx, dataOff, recSize) {
31293
31395
  const b = view.getInt32(dataOff + 12, true);
31294
31396
  const clockwise = rCtx.state.arcDirection === 2;
31295
31397
  const unframed = uprightFixBox(rCtx, l, t, r, b);
31296
- const inset = insideFrameInset(rCtx, unframed);
31398
+ const inset = insideFrameInset(rCtx, unframed, false, rCtx.state.arcDirection === 2);
31297
31399
  const framed = inset ? insetFixBox(unframed, inset) : unframed;
31298
31400
  const params = inset ? { cx: (framed.ax + framed.exx / 2) / 16, cy: (framed.ay + framed.eyy / 2) / 16, rx: Math.abs(framed.exx) / 32, ry: Math.abs(framed.eyy) / 32, rotation: 0 } : hasWorldRotation(rCtx) ? gdiEllipseParams(rCtx, (l + r) / 2, (t + b) / 2, Math.abs(r - l) / 2, Math.abs(b - t) / 2) : {
31299
31401
  cx: gmx(rCtx, (l + r) / 2),
@@ -31343,7 +31445,10 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
31343
31445
  const endAngle = fullEllipse ? startAngle + (clockwise ? 2 : -2) * Math.PI : Math.atan2((endY - cyA) / (ry || 1), (endX - cxA) / (rx || 1));
31344
31446
  const rotated = hasWorldRotation(rCtx);
31345
31447
  const unframed = fixBox(rCtx, l, t, r, b);
31346
- const inset = insideFrameInset(rCtx, unframed);
31448
+ if (recType !== EMR_ARCTO && insideFramePenTooWide(rCtx, unframed)) {
31449
+ return true;
31450
+ }
31451
+ const inset = insideFrameInset(rCtx, unframed, false, rCtx.state.arcDirection === 2);
31347
31452
  const framed = inset ? insetFixBox(unframed, inset) : unframed;
31348
31453
  const params = inset ? { cx: (framed.ax + framed.exx / 2) / 16, cy: (framed.ay + framed.eyy / 2) / 16, rx: Math.abs(framed.exx) / 32, ry: Math.abs(framed.eyy) / 32, rotation: 0 } : rotated ? gdiEllipseParams(rCtx, cxA, cyA, rx, ry) : {
31349
31454
  cx: gmx(rCtx, cxA),
@@ -31374,20 +31479,25 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
31374
31479
  }
31375
31480
  };
31376
31481
  const kind = isArcTo ? "arcto" : recType === EMR_PIE ? "pie" : recType === EMR_CHORD ? "chord" : "arc";
31377
- const radialOnBox = (p) => {
31482
+ const devM = gdiDeviceMatrix(rCtx);
31483
+ const rawFix = (x, y) => [(devM[0] * x + devM[2] * y + devM[4]) * 16, (devM[1] * x + devM[3] * y + devM[5]) * 16];
31484
+ const radialOnBox = (p, raw) => {
31378
31485
  if (!inset) {
31379
31486
  return p;
31380
31487
  }
31381
- const kx = unframed.exx !== 0 ? framed.exx / unframed.exx : 1;
31382
- const ky = unframed.eyy !== 0 ? framed.eyy / unframed.eyy : 1;
31383
- return [framed.ax + framed.exx / 2 + (p[0] - (unframed.ax + unframed.exx / 2)) * kx, framed.ay + framed.eyy / 2 + (p[1] - (unframed.ay + unframed.eyy / 2)) * ky];
31488
+ const [rl, rt] = rawFix(l, t);
31489
+ const [rr, rb] = rawFix(r, b);
31490
+ const kx = rr !== rl ? framed.exx / (rr - rl) : 1;
31491
+ const ky = rb !== rt ? framed.eyy / (rb - rt) : 1;
31492
+ const snap = (v) => Math.abs(v) < 1e-6 ? 0 : v;
31493
+ return [framed.ax + framed.exx / 2 + snap(raw[0] - (rl + rr) / 2) * kx, framed.ay + framed.eyy / 2 + snap(raw[1] - (rt + rb) / 2) * ky];
31384
31494
  };
31385
31495
  const rasterArgs = (immediate = false) => ({
31386
31496
  box: inset ? framed : immediate && needsFill ? curvedFixBox(rCtx, l, t, r, b) : unframed,
31387
- s: radialOnBox(fixPoint(rCtx, startX, startY)),
31497
+ s: radialOnBox(fixPoint(rCtx, startX, startY), rawFix(startX, startY)),
31388
31498
  // Device FIX rounding can separate distinct radial points on the
31389
31499
  // same logical ray. Preserve their proven endpoint identity.
31390
- e: fullEllipse ? radialOnBox(fixPoint(rCtx, startX, startY)) : radialOnBox(fixPoint(rCtx, endX, endY)),
31500
+ e: fullEllipse ? radialOnBox(fixPoint(rCtx, startX, startY), rawFix(startX, startY)) : radialOnBox(fixPoint(rCtx, endX, endY), rawFix(endX, endY)),
31391
31501
  from: currentFix(rCtx)
31392
31502
  });
31393
31503
  if (inPath) {
@@ -39684,6 +39794,7 @@ function compatBox(p, l, t, r, b, opts = {}) {
39684
39794
  if ((p.rCtx.state.penStyle & 15) === PS_INSIDEFRAME2) {
39685
39795
  const w = Math.round(penDeviceWidth(p.rCtx) / p.kx);
39686
39796
  if (w > 1) {
39797
+ const whole = { ...box };
39687
39798
  const matrix = gdiDeviceMatrix(p.rCtx);
39688
39799
  const wx = Math.round(Math.abs(p.rCtx.state.penWidth * matrix[0]) / p.kx * 16);
39689
39800
  const wy = Math.round(Math.abs(p.rCtx.state.penWidth * matrix[3]) / p.ky * 16);
@@ -39697,14 +39808,21 @@ function compatBox(p, l, t, r, b, opts = {}) {
39697
39808
  if (half) {
39698
39809
  box.halfX = true;
39699
39810
  }
39811
+ if (opts.clampEmpty && (box.x1 < box.x0 || box.y1 < box.y0)) {
39812
+ return { x0: whole.x0, y0: whole.y0, x1: whole.x1 + Math.round(ux), y1: whole.y1 + Math.round(uy) };
39813
+ }
39700
39814
  }
39701
39815
  }
39702
39816
  return box;
39703
39817
  }
39704
- function fixBoxOf(box) {
39705
- const fix = axisBox(box.x0, box.y0, Math.max(box.x0, box.x1), Math.max(box.y0, box.y1));
39818
+ function fixBoxOf(box, cornerExact, keepInverted = false) {
39819
+ const fix = keepInverted ? axisBox(box.x0, box.y0, box.x1, box.y1) : axisBox(box.x0, box.y0, Math.max(box.x0, box.x1), Math.max(box.y0, box.y1));
39706
39820
  if (box.halfX) {
39707
39821
  fix.halfX = true;
39822
+ fix.halfXCompat = true;
39823
+ }
39824
+ if (cornerExact) {
39825
+ fix.cornerExact = cornerExact;
39708
39826
  }
39709
39827
  return fix;
39710
39828
  }
@@ -39768,7 +39886,8 @@ function compatCorner(p, w, h, box, logical) {
39768
39886
  const width2 = box.x1 - box.x0, height2 = box.y1 - box.y0;
39769
39887
  const fullW2 = Math.abs((logical[2] - logical[0]) * m[0]) * 16 || width2;
39770
39888
  const fullH2 = Math.abs((logical[3] - logical[1]) * m[3]) * 16 || height2;
39771
- return [Math.floor(Math.min(Math.abs(w * m[0]) * 16, fullW2) * width2 / fullW2), Math.floor(Math.min(Math.abs(h * m[3]) * 16, fullH2) * height2 / fullH2)];
39889
+ const cornerW = Math.min(Math.abs(w * m[0]) * 16, fullW2) * width2 / fullW2;
39890
+ return [Math.floor(cornerW), Math.floor(Math.min(Math.abs(h * m[3]) * 16, fullH2) * height2 / fullH2), [cornerW, Math.min(Math.abs(h * m[3]) * 16, fullH2) * height2 / fullH2]];
39772
39891
  }
39773
39892
  const width = box.x1 - box.x0, height = box.y1 - box.y0;
39774
39893
  const fullW = Math.abs((logical[2] - logical[0]) * m[0]) * 16 || width + ux;
@@ -39777,11 +39896,11 @@ function compatCorner(p, w, h, box, logical) {
39777
39896
  return penIsCosmetic(p.rCtx) && !penIsNull(p) ? scaled2 : [Math.floor(scaled2[0]), Math.floor(scaled2[1])];
39778
39897
  }
39779
39898
  function wmfRoundRect(p, l, t, r, b, w, h) {
39780
- const box = compatBox(p, l, t, r, b, { curved: true, half: true });
39899
+ const box = compatBox(p, l, t, r, b, { curved: true, half: true, clampEmpty: true });
39781
39900
  if (box.x1 < box.x0 || box.y1 < box.y0) {
39782
39901
  return;
39783
39902
  }
39784
- const [cw, ch] = compatCorner(p, w, h, box, [l, t, r, b]);
39903
+ const [cw, ch, half] = compatCorner(p, w, h, box, [l, t, r, b]);
39785
39904
  const cr = canvasRect(box);
39786
39905
  paintGdiShape(p.rCtx, {
39787
39906
  build: (c) => {
@@ -39806,14 +39925,14 @@ function wmfRoundRect(p, l, t, r, b, w, h) {
39806
39925
  c.ellipse(cr.x + ex, cr.y + ey, ex, ey, 0, 2 * q, 3 * q);
39807
39926
  c.closePath();
39808
39927
  },
39809
- raster: () => roundRectRasterPath(fixBoxOf(box), cw, ch, clockwiseOf(p), w === 0 || h === 0, !penIsNull(p) && penIsCosmetic(p.rCtx)),
39928
+ raster: () => roundRectRasterPath(fixBoxOf(box, half), cw, ch, clockwiseOf(p), w === 0 || h === 0, !penIsNull(p) && penIsCosmetic(p.rCtx)),
39810
39929
  roundPen: true,
39811
39930
  fill: true,
39812
39931
  stroke: true
39813
39932
  });
39814
39933
  }
39815
39934
  function wmfEllipse(p, l, t, r, b) {
39816
- const box = compatBox(p, l, t, r, b, { curved: true, half: true });
39935
+ const box = compatBox(p, l, t, r, b, { curved: true, half: true, clampEmpty: true });
39817
39936
  if (box.x1 < box.x0 || box.y1 < box.y0) {
39818
39937
  return;
39819
39938
  }
@@ -39829,9 +39948,9 @@ function wmfEllipse(p, l, t, r, b) {
39829
39948
  stroke: true
39830
39949
  });
39831
39950
  }
39832
- function compatArc(p, kind, l, t, r, b, xs, ys, xe, ye) {
39833
- const box = compatBox(p, l, t, r, b, { curved: kind === "chord" || kind === "pie", roundFrame: true });
39834
- if (box.x1 < box.x0 || box.y1 < box.y0) {
39951
+ function compatArc(p, kind, l, t, r, b, xs, ys, xe, ye, keepInverted = false) {
39952
+ const box = compatBox(p, l, t, r, b, { curved: kind === "chord" || kind === "pie", roundFrame: true, half: true });
39953
+ if (box.y1 < box.y0 || !keepInverted && box.x1 < box.x0) {
39835
39954
  return null;
39836
39955
  }
39837
39956
  const m = gdiDeviceMatrix(p.rCtx);