emf-converter 4.20.2 → 4.20.3

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/browser.js CHANGED
@@ -29019,7 +29019,7 @@ var MonoStubContour = class {
29019
29019
  constructor(o) {
29020
29020
  this.points = Array.from(o.xs, (x, i) => [x / 64 - 0.5, o.ys[i] / 64 - 0.5]);
29021
29021
  }
29022
- isStub(flipped, scan, crossing, lo, hi, precision) {
29022
+ isStub(flipped, scan, crossing, lo, hi, precision, _opposite) {
29023
29023
  const points = this.points;
29024
29024
  const n = points.length;
29025
29025
  const point = (i) => flipped ? [points[i][1], points[i][0]] : points[i];
@@ -29055,6 +29055,82 @@ var MonoStubContour = class {
29055
29055
  return !(a.side * b.side < 0 && a.continues && b.continues);
29056
29056
  }
29057
29057
  };
29058
+ function convexContour(o) {
29059
+ const edges = [];
29060
+ for (let i = 0; i < o.xs.length; i++) {
29061
+ const j = (i + 1) % o.xs.length;
29062
+ const dx = o.xs[j] - o.xs[i], dy = o.ys[j] - o.ys[i];
29063
+ if (dx || dy) edges.push([dx, dy]);
29064
+ }
29065
+ if (edges.length < 3) return false;
29066
+ const half = (p) => p[1] > 0 || p[1] === 0 && p[0] >= 0 ? 0 : 1;
29067
+ let direction = 0, revolutions = 0;
29068
+ for (let i = 0; i < edges.length; i++) {
29069
+ const a = edges[i], b = edges[(i + 1) % edges.length];
29070
+ const cross = a[0] * b[1] - a[1] * b[0];
29071
+ if (!cross) {
29072
+ if (a[0] * b[0] + a[1] * b[1] < 0) return false;
29073
+ continue;
29074
+ }
29075
+ const turn = Math.sign(cross);
29076
+ if (direction && direction !== turn) return false;
29077
+ direction = turn;
29078
+ if (half(a) !== half(b) && half(a) === (turn > 0 ? 1 : 0)) revolutions++;
29079
+ }
29080
+ return direction !== 0 && revolutions === 1;
29081
+ }
29082
+ var MonoStubContours = class _MonoStubContours {
29083
+ constructor(contours) {
29084
+ this.contours = contours;
29085
+ }
29086
+ static create(o) {
29087
+ if (o.endPts.length > 64) return null;
29088
+ if (Array.from(o.onCurve).some((p) => !p)) return null;
29089
+ if (o.endPts.length === 1) return new MonoStubContour(o);
29090
+ const contours = [];
29091
+ const boxes = [];
29092
+ let start = 0;
29093
+ for (const end of o.endPts) {
29094
+ const xs = [], ys = [], onCurve = [];
29095
+ for (let i = start; i <= end; i++) {
29096
+ xs.push(o.xs[i]);
29097
+ ys.push(o.ys[i]);
29098
+ onCurve.push(o.onCurve[i]);
29099
+ }
29100
+ const part = { xs, ys, onCurve, endPts: [end - start] };
29101
+ start = end + 1;
29102
+ if (!convexContour(part)) return null;
29103
+ const box = { xMin: Infinity, xMax: -Infinity, yMin: Infinity, yMax: -Infinity };
29104
+ for (let i = 0; i < part.xs.length; i++) {
29105
+ box.xMin = Math.min(box.xMin, part.xs[i]);
29106
+ box.xMax = Math.max(box.xMax, part.xs[i]);
29107
+ box.yMin = Math.min(box.yMin, part.ys[i]);
29108
+ box.yMax = Math.max(box.yMax, part.ys[i]);
29109
+ }
29110
+ if (boxes.some((b) => box.xMin <= b.xMax + 64 && b.xMin <= box.xMax + 64 && box.yMin <= b.yMax + 64 && b.yMin <= box.yMax + 64)) return null;
29111
+ boxes.push(box);
29112
+ contours.push(new MonoStubContour(part));
29113
+ }
29114
+ return new _MonoStubContours(contours);
29115
+ }
29116
+ isStub(flipped, scan, crossing, lo, hi, precision, opposite) {
29117
+ let owner = -1, otherOwner = -1, result = null;
29118
+ for (let i = 0; i < this.contours.length; i++) {
29119
+ const a = this.contours[i].isStub(flipped, scan, crossing, lo, hi, precision);
29120
+ const b = this.contours[i].isStub(flipped, scan, opposite, lo, hi, precision);
29121
+ if (a !== null) {
29122
+ if (owner >= 0) return null;
29123
+ owner = i;
29124
+ result = a;
29125
+ }
29126
+ if (b !== null) {
29127
+ if (otherOwner >= 0) return null;
29128
+ otherOwner = i;
29129
+ }
29130
+ }
29131
+ return owner >= 0 && owner === otherOwner ? result : null;
29132
+ }
29133
+ };
29058
29134
  function monoBox(o) {
29059
29135
  const n = o.xs.length;
29060
29136
  if (n === 0) {
@@ -29104,7 +29180,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29104
29180
  const at = (col, row2) => (height - 1 - row2) * width + col;
29105
29181
  const r = new Raster(dropout);
29106
29182
  const P = r.precision;
29107
- const monoContour = stubOvershoot && (dropout === 1 || dropout === 4 || dropout === 5) && local.endPts.length === 1 && Array.from(local.onCurve).every(Boolean) ? new MonoStubContour(local) : null;
29183
+ const monoContour = stubOvershoot && (dropout === 1 || dropout === 4 || dropout === 5) ? MonoStubContours.create(local) : null;
29108
29184
  const smartPixel = (raster, x1, x2) => {
29109
29185
  if (monoContour && smartCrossings26Dot6) {
29110
29186
  const step = P / 64;
@@ -29147,7 +29223,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29147
29223
  break;
29148
29224
  case 1:
29149
29225
  case 5:
29150
- const stub = monoContour && box.collapsedX ? false : monoContour?.isStub(false, y, x1 / P, e2 / P, e1 / P, P);
29226
+ const stub = monoContour && box.collapsedX ? false : monoContour?.isStub(false, y, x1 / P, e2 / P, e1 / P, P, x2 / P);
29151
29227
  if (stub === true) return;
29152
29228
  if (stub == null && left.next === right && left.height <= 0 && !(stubOvershoot && left.flags & OVERSHOOT_TOP && x2 - x1 >= r.half)) {
29153
29229
  return;
@@ -29208,7 +29284,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29208
29284
  break;
29209
29285
  case 1:
29210
29286
  case 5:
29211
- const stub = monoContour && box.collapsedY ? false : monoContour?.isStub(true, col, x1 / P, e2 / P, e1 / P, P);
29287
+ const stub = monoContour && box.collapsedY ? false : monoContour?.isStub(true, col, x1 / P, e2 / P, e1 / P, P, x2 / P);
29212
29288
  if (stub === true) return;
29213
29289
  if (stub == null && left.next === right && left.height <= 0 && !(stubOvershoot && left.flags & OVERSHOOT_TOP && x2 - x1 >= h.half)) {
29214
29290
  return;
@@ -40756,22 +40832,23 @@ function drawPlusStringWithEngine(rCtx, font, text, layoutX, layoutY, layoutW, l
40756
40832
  }
40757
40833
  const { realized, emPx, m, unhinted } = ef;
40758
40834
  const codes = Array.from(text, (character) => character.codePointAt(0));
40759
- if (format && (alignment !== 0 || format.lineAlignment !== 0) && unhinted && m[0] === 1 && m[3] === 1 && emPx === realized.ppem) {
40835
+ if (format && (alignment !== 0 || format.lineAlignment !== 0) && unhinted && m[0] === m[3] && Math.fround(emPx) === realized.ppem) {
40760
40836
  const aligned = layoutPlusAlignedString(
40761
40837
  realized,
40762
40838
  codes,
40763
40839
  format,
40764
- layoutX + m[4],
40765
- layoutY + m[5],
40766
- layoutW,
40767
- layoutH
40840
+ m[0] * layoutX + m[4],
40841
+ m[3] * layoutY + m[5],
40842
+ m[0] * layoutW,
40843
+ m[3] * layoutH
40768
40844
  );
40769
40845
  if (aligned) return paintPlusEngineRun(rCtx, ef, { codes, glyphIndices: false, ...aligned, dy: null });
40770
40846
  }
40771
40847
  if (alignment !== 0) return false;
40772
40848
  const ttf = realized.ttf;
40773
40849
  const exactAscent = emPx * ttf.winAscent / ttf.unitsPerEm;
40774
- const ascent = unhinted ? Math.round(exactAscent) : Math.ceil(exactAscent);
40850
+ const clearTypeCell = realized.mode === "cleartype" && !realized.syntheticBold && !realized.syntheticItalic && emPx === realized.ppem && m[0] === 1 && m[3] === 1 && Number.isInteger(layoutY + m[5]) && (format?.lineAlignment ?? 0) === 0;
40851
+ const ascent = unhinted ? Math.round(exactAscent) : clearTypeCell ? Math.max(Math.round(exactAscent), realized.ascent) : Math.ceil(exactAscent);
40775
40852
  let x = m[0] * layoutX + m[4] + emPx * (format?.leadingMargin ?? PLUS_LEADING_EM);
40776
40853
  if (!unhinted) x = Math.round(x);
40777
40854
  const y = m[3] * layoutY + m[5] + ascent;
package/dist/browser.mjs CHANGED
@@ -29017,7 +29017,7 @@ var MonoStubContour = class {
29017
29017
  constructor(o) {
29018
29018
  this.points = Array.from(o.xs, (x, i) => [x / 64 - 0.5, o.ys[i] / 64 - 0.5]);
29019
29019
  }
29020
- isStub(flipped, scan, crossing, lo, hi, precision) {
29020
+ isStub(flipped, scan, crossing, lo, hi, precision, _opposite) {
29021
29021
  const points = this.points;
29022
29022
  const n = points.length;
29023
29023
  const point = (i) => flipped ? [points[i][1], points[i][0]] : points[i];
@@ -29053,6 +29053,82 @@ var MonoStubContour = class {
29053
29053
  return !(a.side * b.side < 0 && a.continues && b.continues);
29054
29054
  }
29055
29055
  };
29056
+ function convexContour(o) {
29057
+ const edges = [];
29058
+ for (let i = 0; i < o.xs.length; i++) {
29059
+ const j = (i + 1) % o.xs.length;
29060
+ const dx = o.xs[j] - o.xs[i], dy = o.ys[j] - o.ys[i];
29061
+ if (dx || dy) edges.push([dx, dy]);
29062
+ }
29063
+ if (edges.length < 3) return false;
29064
+ const half = (p) => p[1] > 0 || p[1] === 0 && p[0] >= 0 ? 0 : 1;
29065
+ let direction = 0, revolutions = 0;
29066
+ for (let i = 0; i < edges.length; i++) {
29067
+ const a = edges[i], b = edges[(i + 1) % edges.length];
29068
+ const cross = a[0] * b[1] - a[1] * b[0];
29069
+ if (!cross) {
29070
+ if (a[0] * b[0] + a[1] * b[1] < 0) return false;
29071
+ continue;
29072
+ }
29073
+ const turn = Math.sign(cross);
29074
+ if (direction && direction !== turn) return false;
29075
+ direction = turn;
29076
+ if (half(a) !== half(b) && half(a) === (turn > 0 ? 1 : 0)) revolutions++;
29077
+ }
29078
+ return direction !== 0 && revolutions === 1;
29079
+ }
29080
+ var MonoStubContours = class _MonoStubContours {
29081
+ constructor(contours) {
29082
+ this.contours = contours;
29083
+ }
29084
+ static create(o) {
29085
+ if (o.endPts.length > 64) return null;
29086
+ if (Array.from(o.onCurve).some((p) => !p)) return null;
29087
+ if (o.endPts.length === 1) return new MonoStubContour(o);
29088
+ const contours = [];
29089
+ const boxes = [];
29090
+ let start = 0;
29091
+ for (const end of o.endPts) {
29092
+ const xs = [], ys = [], onCurve = [];
29093
+ for (let i = start; i <= end; i++) {
29094
+ xs.push(o.xs[i]);
29095
+ ys.push(o.ys[i]);
29096
+ onCurve.push(o.onCurve[i]);
29097
+ }
29098
+ const part = { xs, ys, onCurve, endPts: [end - start] };
29099
+ start = end + 1;
29100
+ if (!convexContour(part)) return null;
29101
+ const box = { xMin: Infinity, xMax: -Infinity, yMin: Infinity, yMax: -Infinity };
29102
+ for (let i = 0; i < part.xs.length; i++) {
29103
+ box.xMin = Math.min(box.xMin, part.xs[i]);
29104
+ box.xMax = Math.max(box.xMax, part.xs[i]);
29105
+ box.yMin = Math.min(box.yMin, part.ys[i]);
29106
+ box.yMax = Math.max(box.yMax, part.ys[i]);
29107
+ }
29108
+ if (boxes.some((b) => box.xMin <= b.xMax + 64 && b.xMin <= box.xMax + 64 && box.yMin <= b.yMax + 64 && b.yMin <= box.yMax + 64)) return null;
29109
+ boxes.push(box);
29110
+ contours.push(new MonoStubContour(part));
29111
+ }
29112
+ return new _MonoStubContours(contours);
29113
+ }
29114
+ isStub(flipped, scan, crossing, lo, hi, precision, opposite) {
29115
+ let owner = -1, otherOwner = -1, result = null;
29116
+ for (let i = 0; i < this.contours.length; i++) {
29117
+ const a = this.contours[i].isStub(flipped, scan, crossing, lo, hi, precision);
29118
+ const b = this.contours[i].isStub(flipped, scan, opposite, lo, hi, precision);
29119
+ if (a !== null) {
29120
+ if (owner >= 0) return null;
29121
+ owner = i;
29122
+ result = a;
29123
+ }
29124
+ if (b !== null) {
29125
+ if (otherOwner >= 0) return null;
29126
+ otherOwner = i;
29127
+ }
29128
+ }
29129
+ return owner >= 0 && owner === otherOwner ? result : null;
29130
+ }
29131
+ };
29056
29132
  function monoBox(o) {
29057
29133
  const n = o.xs.length;
29058
29134
  if (n === 0) {
@@ -29102,7 +29178,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29102
29178
  const at = (col, row2) => (height - 1 - row2) * width + col;
29103
29179
  const r = new Raster(dropout);
29104
29180
  const P = r.precision;
29105
- const monoContour = stubOvershoot && (dropout === 1 || dropout === 4 || dropout === 5) && local.endPts.length === 1 && Array.from(local.onCurve).every(Boolean) ? new MonoStubContour(local) : null;
29181
+ const monoContour = stubOvershoot && (dropout === 1 || dropout === 4 || dropout === 5) ? MonoStubContours.create(local) : null;
29106
29182
  const smartPixel = (raster, x1, x2) => {
29107
29183
  if (monoContour && smartCrossings26Dot6) {
29108
29184
  const step = P / 64;
@@ -29145,7 +29221,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29145
29221
  break;
29146
29222
  case 1:
29147
29223
  case 5:
29148
- const stub = monoContour && box.collapsedX ? false : monoContour?.isStub(false, y, x1 / P, e2 / P, e1 / P, P);
29224
+ const stub = monoContour && box.collapsedX ? false : monoContour?.isStub(false, y, x1 / P, e2 / P, e1 / P, P, x2 / P);
29149
29225
  if (stub === true) return;
29150
29226
  if (stub == null && left.next === right && left.height <= 0 && !(stubOvershoot && left.flags & OVERSHOOT_TOP && x2 - x1 >= r.half)) {
29151
29227
  return;
@@ -29206,7 +29282,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29206
29282
  break;
29207
29283
  case 1:
29208
29284
  case 5:
29209
- const stub = monoContour && box.collapsedY ? false : monoContour?.isStub(true, col, x1 / P, e2 / P, e1 / P, P);
29285
+ const stub = monoContour && box.collapsedY ? false : monoContour?.isStub(true, col, x1 / P, e2 / P, e1 / P, P, x2 / P);
29210
29286
  if (stub === true) return;
29211
29287
  if (stub == null && left.next === right && left.height <= 0 && !(stubOvershoot && left.flags & OVERSHOOT_TOP && x2 - x1 >= h.half)) {
29212
29288
  return;
@@ -40754,22 +40830,23 @@ function drawPlusStringWithEngine(rCtx, font, text, layoutX, layoutY, layoutW, l
40754
40830
  }
40755
40831
  const { realized, emPx, m, unhinted } = ef;
40756
40832
  const codes = Array.from(text, (character) => character.codePointAt(0));
40757
- if (format && (alignment !== 0 || format.lineAlignment !== 0) && unhinted && m[0] === 1 && m[3] === 1 && emPx === realized.ppem) {
40833
+ if (format && (alignment !== 0 || format.lineAlignment !== 0) && unhinted && m[0] === m[3] && Math.fround(emPx) === realized.ppem) {
40758
40834
  const aligned = layoutPlusAlignedString(
40759
40835
  realized,
40760
40836
  codes,
40761
40837
  format,
40762
- layoutX + m[4],
40763
- layoutY + m[5],
40764
- layoutW,
40765
- layoutH
40838
+ m[0] * layoutX + m[4],
40839
+ m[3] * layoutY + m[5],
40840
+ m[0] * layoutW,
40841
+ m[3] * layoutH
40766
40842
  );
40767
40843
  if (aligned) return paintPlusEngineRun(rCtx, ef, { codes, glyphIndices: false, ...aligned, dy: null });
40768
40844
  }
40769
40845
  if (alignment !== 0) return false;
40770
40846
  const ttf = realized.ttf;
40771
40847
  const exactAscent = emPx * ttf.winAscent / ttf.unitsPerEm;
40772
- const ascent = unhinted ? Math.round(exactAscent) : Math.ceil(exactAscent);
40848
+ const clearTypeCell = realized.mode === "cleartype" && !realized.syntheticBold && !realized.syntheticItalic && emPx === realized.ppem && m[0] === 1 && m[3] === 1 && Number.isInteger(layoutY + m[5]) && (format?.lineAlignment ?? 0) === 0;
40849
+ const ascent = unhinted ? Math.round(exactAscent) : clearTypeCell ? Math.max(Math.round(exactAscent), realized.ascent) : Math.ceil(exactAscent);
40773
40850
  let x = m[0] * layoutX + m[4] + emPx * (format?.leadingMargin ?? PLUS_LEADING_EM);
40774
40851
  if (!unhinted) x = Math.round(x);
40775
40852
  const y = m[3] * layoutY + m[5] + ascent;
package/dist/index.js CHANGED
@@ -29020,7 +29020,7 @@ var MonoStubContour = class {
29020
29020
  constructor(o) {
29021
29021
  this.points = Array.from(o.xs, (x, i) => [x / 64 - 0.5, o.ys[i] / 64 - 0.5]);
29022
29022
  }
29023
- isStub(flipped, scan, crossing, lo, hi, precision) {
29023
+ isStub(flipped, scan, crossing, lo, hi, precision, _opposite) {
29024
29024
  const points = this.points;
29025
29025
  const n = points.length;
29026
29026
  const point = (i) => flipped ? [points[i][1], points[i][0]] : points[i];
@@ -29056,6 +29056,82 @@ var MonoStubContour = class {
29056
29056
  return !(a.side * b.side < 0 && a.continues && b.continues);
29057
29057
  }
29058
29058
  };
29059
+ function convexContour(o) {
29060
+ const edges = [];
29061
+ for (let i = 0; i < o.xs.length; i++) {
29062
+ const j = (i + 1) % o.xs.length;
29063
+ const dx = o.xs[j] - o.xs[i], dy = o.ys[j] - o.ys[i];
29064
+ if (dx || dy) edges.push([dx, dy]);
29065
+ }
29066
+ if (edges.length < 3) return false;
29067
+ const half = (p) => p[1] > 0 || p[1] === 0 && p[0] >= 0 ? 0 : 1;
29068
+ let direction = 0, revolutions = 0;
29069
+ for (let i = 0; i < edges.length; i++) {
29070
+ const a = edges[i], b = edges[(i + 1) % edges.length];
29071
+ const cross = a[0] * b[1] - a[1] * b[0];
29072
+ if (!cross) {
29073
+ if (a[0] * b[0] + a[1] * b[1] < 0) return false;
29074
+ continue;
29075
+ }
29076
+ const turn = Math.sign(cross);
29077
+ if (direction && direction !== turn) return false;
29078
+ direction = turn;
29079
+ if (half(a) !== half(b) && half(a) === (turn > 0 ? 1 : 0)) revolutions++;
29080
+ }
29081
+ return direction !== 0 && revolutions === 1;
29082
+ }
29083
+ var MonoStubContours = class _MonoStubContours {
29084
+ constructor(contours) {
29085
+ this.contours = contours;
29086
+ }
29087
+ static create(o) {
29088
+ if (o.endPts.length > 64) return null;
29089
+ if (Array.from(o.onCurve).some((p) => !p)) return null;
29090
+ if (o.endPts.length === 1) return new MonoStubContour(o);
29091
+ const contours = [];
29092
+ const boxes = [];
29093
+ let start = 0;
29094
+ for (const end of o.endPts) {
29095
+ const xs = [], ys = [], onCurve = [];
29096
+ for (let i = start; i <= end; i++) {
29097
+ xs.push(o.xs[i]);
29098
+ ys.push(o.ys[i]);
29099
+ onCurve.push(o.onCurve[i]);
29100
+ }
29101
+ const part = { xs, ys, onCurve, endPts: [end - start] };
29102
+ start = end + 1;
29103
+ if (!convexContour(part)) return null;
29104
+ const box = { xMin: Infinity, xMax: -Infinity, yMin: Infinity, yMax: -Infinity };
29105
+ for (let i = 0; i < part.xs.length; i++) {
29106
+ box.xMin = Math.min(box.xMin, part.xs[i]);
29107
+ box.xMax = Math.max(box.xMax, part.xs[i]);
29108
+ box.yMin = Math.min(box.yMin, part.ys[i]);
29109
+ box.yMax = Math.max(box.yMax, part.ys[i]);
29110
+ }
29111
+ if (boxes.some((b) => box.xMin <= b.xMax + 64 && b.xMin <= box.xMax + 64 && box.yMin <= b.yMax + 64 && b.yMin <= box.yMax + 64)) return null;
29112
+ boxes.push(box);
29113
+ contours.push(new MonoStubContour(part));
29114
+ }
29115
+ return new _MonoStubContours(contours);
29116
+ }
29117
+ isStub(flipped, scan, crossing, lo, hi, precision, opposite) {
29118
+ let owner = -1, otherOwner = -1, result = null;
29119
+ for (let i = 0; i < this.contours.length; i++) {
29120
+ const a = this.contours[i].isStub(flipped, scan, crossing, lo, hi, precision);
29121
+ const b = this.contours[i].isStub(flipped, scan, opposite, lo, hi, precision);
29122
+ if (a !== null) {
29123
+ if (owner >= 0) return null;
29124
+ owner = i;
29125
+ result = a;
29126
+ }
29127
+ if (b !== null) {
29128
+ if (otherOwner >= 0) return null;
29129
+ otherOwner = i;
29130
+ }
29131
+ }
29132
+ return owner >= 0 && owner === otherOwner ? result : null;
29133
+ }
29134
+ };
29059
29135
  function monoBox(o) {
29060
29136
  const n = o.xs.length;
29061
29137
  if (n === 0) {
@@ -29105,7 +29181,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29105
29181
  const at = (col, row2) => (height - 1 - row2) * width + col;
29106
29182
  const r = new Raster(dropout);
29107
29183
  const P = r.precision;
29108
- const monoContour = stubOvershoot && (dropout === 1 || dropout === 4 || dropout === 5) && local.endPts.length === 1 && Array.from(local.onCurve).every(Boolean) ? new MonoStubContour(local) : null;
29184
+ const monoContour = stubOvershoot && (dropout === 1 || dropout === 4 || dropout === 5) ? MonoStubContours.create(local) : null;
29109
29185
  const smartPixel = (raster, x1, x2) => {
29110
29186
  if (monoContour && smartCrossings26Dot6) {
29111
29187
  const step = P / 64;
@@ -29148,7 +29224,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29148
29224
  break;
29149
29225
  case 1:
29150
29226
  case 5:
29151
- const stub = monoContour && box.collapsedX ? false : monoContour?.isStub(false, y, x1 / P, e2 / P, e1 / P, P);
29227
+ const stub = monoContour && box.collapsedX ? false : monoContour?.isStub(false, y, x1 / P, e2 / P, e1 / P, P, x2 / P);
29152
29228
  if (stub === true) return;
29153
29229
  if (stub == null && left.next === right && left.height <= 0 && !(stubOvershoot && left.flags & OVERSHOOT_TOP && x2 - x1 >= r.half)) {
29154
29230
  return;
@@ -29209,7 +29285,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29209
29285
  break;
29210
29286
  case 1:
29211
29287
  case 5:
29212
- const stub = monoContour && box.collapsedY ? false : monoContour?.isStub(true, col, x1 / P, e2 / P, e1 / P, P);
29288
+ const stub = monoContour && box.collapsedY ? false : monoContour?.isStub(true, col, x1 / P, e2 / P, e1 / P, P, x2 / P);
29213
29289
  if (stub === true) return;
29214
29290
  if (stub == null && left.next === right && left.height <= 0 && !(stubOvershoot && left.flags & OVERSHOOT_TOP && x2 - x1 >= h.half)) {
29215
29291
  return;
@@ -40757,22 +40833,23 @@ function drawPlusStringWithEngine(rCtx, font, text, layoutX, layoutY, layoutW, l
40757
40833
  }
40758
40834
  const { realized, emPx, m, unhinted } = ef;
40759
40835
  const codes = Array.from(text, (character) => character.codePointAt(0));
40760
- if (format && (alignment !== 0 || format.lineAlignment !== 0) && unhinted && m[0] === 1 && m[3] === 1 && emPx === realized.ppem) {
40836
+ if (format && (alignment !== 0 || format.lineAlignment !== 0) && unhinted && m[0] === m[3] && Math.fround(emPx) === realized.ppem) {
40761
40837
  const aligned = layoutPlusAlignedString(
40762
40838
  realized,
40763
40839
  codes,
40764
40840
  format,
40765
- layoutX + m[4],
40766
- layoutY + m[5],
40767
- layoutW,
40768
- layoutH
40841
+ m[0] * layoutX + m[4],
40842
+ m[3] * layoutY + m[5],
40843
+ m[0] * layoutW,
40844
+ m[3] * layoutH
40769
40845
  );
40770
40846
  if (aligned) return paintPlusEngineRun(rCtx, ef, { codes, glyphIndices: false, ...aligned, dy: null });
40771
40847
  }
40772
40848
  if (alignment !== 0) return false;
40773
40849
  const ttf = realized.ttf;
40774
40850
  const exactAscent = emPx * ttf.winAscent / ttf.unitsPerEm;
40775
- const ascent = unhinted ? Math.round(exactAscent) : Math.ceil(exactAscent);
40851
+ const clearTypeCell = realized.mode === "cleartype" && !realized.syntheticBold && !realized.syntheticItalic && emPx === realized.ppem && m[0] === 1 && m[3] === 1 && Number.isInteger(layoutY + m[5]) && (format?.lineAlignment ?? 0) === 0;
40852
+ const ascent = unhinted ? Math.round(exactAscent) : clearTypeCell ? Math.max(Math.round(exactAscent), realized.ascent) : Math.ceil(exactAscent);
40776
40853
  let x = m[0] * layoutX + m[4] + emPx * (format?.leadingMargin ?? PLUS_LEADING_EM);
40777
40854
  if (!unhinted) x = Math.round(x);
40778
40855
  const y = m[3] * layoutY + m[5] + ascent;
package/dist/index.mjs CHANGED
@@ -29018,7 +29018,7 @@ var MonoStubContour = class {
29018
29018
  constructor(o) {
29019
29019
  this.points = Array.from(o.xs, (x, i) => [x / 64 - 0.5, o.ys[i] / 64 - 0.5]);
29020
29020
  }
29021
- isStub(flipped, scan, crossing, lo, hi, precision) {
29021
+ isStub(flipped, scan, crossing, lo, hi, precision, _opposite) {
29022
29022
  const points = this.points;
29023
29023
  const n = points.length;
29024
29024
  const point = (i) => flipped ? [points[i][1], points[i][0]] : points[i];
@@ -29054,6 +29054,82 @@ var MonoStubContour = class {
29054
29054
  return !(a.side * b.side < 0 && a.continues && b.continues);
29055
29055
  }
29056
29056
  };
29057
+ function convexContour(o) {
29058
+ const edges = [];
29059
+ for (let i = 0; i < o.xs.length; i++) {
29060
+ const j = (i + 1) % o.xs.length;
29061
+ const dx = o.xs[j] - o.xs[i], dy = o.ys[j] - o.ys[i];
29062
+ if (dx || dy) edges.push([dx, dy]);
29063
+ }
29064
+ if (edges.length < 3) return false;
29065
+ const half = (p) => p[1] > 0 || p[1] === 0 && p[0] >= 0 ? 0 : 1;
29066
+ let direction = 0, revolutions = 0;
29067
+ for (let i = 0; i < edges.length; i++) {
29068
+ const a = edges[i], b = edges[(i + 1) % edges.length];
29069
+ const cross = a[0] * b[1] - a[1] * b[0];
29070
+ if (!cross) {
29071
+ if (a[0] * b[0] + a[1] * b[1] < 0) return false;
29072
+ continue;
29073
+ }
29074
+ const turn = Math.sign(cross);
29075
+ if (direction && direction !== turn) return false;
29076
+ direction = turn;
29077
+ if (half(a) !== half(b) && half(a) === (turn > 0 ? 1 : 0)) revolutions++;
29078
+ }
29079
+ return direction !== 0 && revolutions === 1;
29080
+ }
29081
+ var MonoStubContours = class _MonoStubContours {
29082
+ constructor(contours) {
29083
+ this.contours = contours;
29084
+ }
29085
+ static create(o) {
29086
+ if (o.endPts.length > 64) return null;
29087
+ if (Array.from(o.onCurve).some((p) => !p)) return null;
29088
+ if (o.endPts.length === 1) return new MonoStubContour(o);
29089
+ const contours = [];
29090
+ const boxes = [];
29091
+ let start = 0;
29092
+ for (const end of o.endPts) {
29093
+ const xs = [], ys = [], onCurve = [];
29094
+ for (let i = start; i <= end; i++) {
29095
+ xs.push(o.xs[i]);
29096
+ ys.push(o.ys[i]);
29097
+ onCurve.push(o.onCurve[i]);
29098
+ }
29099
+ const part = { xs, ys, onCurve, endPts: [end - start] };
29100
+ start = end + 1;
29101
+ if (!convexContour(part)) return null;
29102
+ const box = { xMin: Infinity, xMax: -Infinity, yMin: Infinity, yMax: -Infinity };
29103
+ for (let i = 0; i < part.xs.length; i++) {
29104
+ box.xMin = Math.min(box.xMin, part.xs[i]);
29105
+ box.xMax = Math.max(box.xMax, part.xs[i]);
29106
+ box.yMin = Math.min(box.yMin, part.ys[i]);
29107
+ box.yMax = Math.max(box.yMax, part.ys[i]);
29108
+ }
29109
+ if (boxes.some((b) => box.xMin <= b.xMax + 64 && b.xMin <= box.xMax + 64 && box.yMin <= b.yMax + 64 && b.yMin <= box.yMax + 64)) return null;
29110
+ boxes.push(box);
29111
+ contours.push(new MonoStubContour(part));
29112
+ }
29113
+ return new _MonoStubContours(contours);
29114
+ }
29115
+ isStub(flipped, scan, crossing, lo, hi, precision, opposite) {
29116
+ let owner = -1, otherOwner = -1, result = null;
29117
+ for (let i = 0; i < this.contours.length; i++) {
29118
+ const a = this.contours[i].isStub(flipped, scan, crossing, lo, hi, precision);
29119
+ const b = this.contours[i].isStub(flipped, scan, opposite, lo, hi, precision);
29120
+ if (a !== null) {
29121
+ if (owner >= 0) return null;
29122
+ owner = i;
29123
+ result = a;
29124
+ }
29125
+ if (b !== null) {
29126
+ if (otherOwner >= 0) return null;
29127
+ otherOwner = i;
29128
+ }
29129
+ }
29130
+ return owner >= 0 && owner === otherOwner ? result : null;
29131
+ }
29132
+ };
29057
29133
  function monoBox(o) {
29058
29134
  const n = o.xs.length;
29059
29135
  if (n === 0) {
@@ -29103,7 +29179,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29103
29179
  const at = (col, row2) => (height - 1 - row2) * width + col;
29104
29180
  const r = new Raster(dropout);
29105
29181
  const P = r.precision;
29106
- const monoContour = stubOvershoot && (dropout === 1 || dropout === 4 || dropout === 5) && local.endPts.length === 1 && Array.from(local.onCurve).every(Boolean) ? new MonoStubContour(local) : null;
29182
+ const monoContour = stubOvershoot && (dropout === 1 || dropout === 4 || dropout === 5) ? MonoStubContours.create(local) : null;
29107
29183
  const smartPixel = (raster, x1, x2) => {
29108
29184
  if (monoContour && smartCrossings26Dot6) {
29109
29185
  const step = P / 64;
@@ -29146,7 +29222,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29146
29222
  break;
29147
29223
  case 1:
29148
29224
  case 5:
29149
- const stub = monoContour && box.collapsedX ? false : monoContour?.isStub(false, y, x1 / P, e2 / P, e1 / P, P);
29225
+ const stub = monoContour && box.collapsedX ? false : monoContour?.isStub(false, y, x1 / P, e2 / P, e1 / P, P, x2 / P);
29150
29226
  if (stub === true) return;
29151
29227
  if (stub == null && left.next === right && left.height <= 0 && !(stubOvershoot && left.flags & OVERSHOOT_TOP && x2 - x1 >= r.half)) {
29152
29228
  return;
@@ -29207,7 +29283,7 @@ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true, smartCrossing
29207
29283
  break;
29208
29284
  case 1:
29209
29285
  case 5:
29210
- const stub = monoContour && box.collapsedY ? false : monoContour?.isStub(true, col, x1 / P, e2 / P, e1 / P, P);
29286
+ const stub = monoContour && box.collapsedY ? false : monoContour?.isStub(true, col, x1 / P, e2 / P, e1 / P, P, x2 / P);
29211
29287
  if (stub === true) return;
29212
29288
  if (stub == null && left.next === right && left.height <= 0 && !(stubOvershoot && left.flags & OVERSHOOT_TOP && x2 - x1 >= h.half)) {
29213
29289
  return;
@@ -40755,22 +40831,23 @@ function drawPlusStringWithEngine(rCtx, font, text, layoutX, layoutY, layoutW, l
40755
40831
  }
40756
40832
  const { realized, emPx, m, unhinted } = ef;
40757
40833
  const codes = Array.from(text, (character) => character.codePointAt(0));
40758
- if (format && (alignment !== 0 || format.lineAlignment !== 0) && unhinted && m[0] === 1 && m[3] === 1 && emPx === realized.ppem) {
40834
+ if (format && (alignment !== 0 || format.lineAlignment !== 0) && unhinted && m[0] === m[3] && Math.fround(emPx) === realized.ppem) {
40759
40835
  const aligned = layoutPlusAlignedString(
40760
40836
  realized,
40761
40837
  codes,
40762
40838
  format,
40763
- layoutX + m[4],
40764
- layoutY + m[5],
40765
- layoutW,
40766
- layoutH
40839
+ m[0] * layoutX + m[4],
40840
+ m[3] * layoutY + m[5],
40841
+ m[0] * layoutW,
40842
+ m[3] * layoutH
40767
40843
  );
40768
40844
  if (aligned) return paintPlusEngineRun(rCtx, ef, { codes, glyphIndices: false, ...aligned, dy: null });
40769
40845
  }
40770
40846
  if (alignment !== 0) return false;
40771
40847
  const ttf = realized.ttf;
40772
40848
  const exactAscent = emPx * ttf.winAscent / ttf.unitsPerEm;
40773
- const ascent = unhinted ? Math.round(exactAscent) : Math.ceil(exactAscent);
40849
+ const clearTypeCell = realized.mode === "cleartype" && !realized.syntheticBold && !realized.syntheticItalic && emPx === realized.ppem && m[0] === 1 && m[3] === 1 && Number.isInteger(layoutY + m[5]) && (format?.lineAlignment ?? 0) === 0;
40850
+ const ascent = unhinted ? Math.round(exactAscent) : clearTypeCell ? Math.max(Math.round(exactAscent), realized.ascent) : Math.ceil(exactAscent);
40774
40851
  let x = m[0] * layoutX + m[4] + emPx * (format?.leadingMargin ?? PLUS_LEADING_EM);
40775
40852
  if (!unhinted) x = Math.round(x);
40776
40853
  const y = m[3] * layoutY + m[5] + ascent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emf-converter",
3
- "version": "4.20.2",
3
+ "version": "4.20.3",
4
4
  "description": "Convert EMF/WMF metafile binaries to PNG or JPEG data URLs, or SVG (markup, data URL, React/JSX)",
5
5
  "keywords": [
6
6
  "canvas",