html2canvas-pro 2.3.1 → 2.3.2

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * html2canvas-pro 2.3.1 <https://yorickshan.github.io/html2canvas-pro/>
2
+ * html2canvas-pro 2.3.2 <https://yorickshan.github.io/html2canvas-pro/>
3
3
  * Copyright (c) 2024-present yorickshan and html2canvas-pro contributors
4
4
  * Released under MIT License
5
5
  */
@@ -8947,60 +8947,6 @@ const calculateBackgroundRepeatPath = (repeat, [x, y], [width, height], backgrou
8947
8947
  }
8948
8948
  };
8949
8949
  //#endregion
8950
- //#region src/core/util.ts
8951
- const SMALL_IMAGE = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
8952
- //#endregion
8953
- //#region src/render/font-metrics.ts
8954
- const SAMPLE_TEXT = "Hidden Text";
8955
- var FontMetrics = class {
8956
- constructor(document) {
8957
- this._data = {};
8958
- this._document = document;
8959
- }
8960
- parseMetrics(fontFamily, fontSize) {
8961
- const container = this._document.createElement("div");
8962
- const img = this._document.createElement("img");
8963
- const span = this._document.createElement("span");
8964
- const body = this._document.body;
8965
- container.style.visibility = "hidden";
8966
- container.style.fontFamily = fontFamily;
8967
- container.style.fontSize = fontSize;
8968
- container.style.margin = "0";
8969
- container.style.padding = "0";
8970
- container.style.whiteSpace = "nowrap";
8971
- body.appendChild(container);
8972
- img.src = SMALL_IMAGE;
8973
- img.width = 1;
8974
- img.height = 1;
8975
- img.style.margin = "0";
8976
- img.style.padding = "0";
8977
- img.style.verticalAlign = "baseline";
8978
- span.style.fontFamily = fontFamily;
8979
- span.style.fontSize = fontSize;
8980
- span.style.margin = "0";
8981
- span.style.padding = "0";
8982
- span.appendChild(this._document.createTextNode(SAMPLE_TEXT));
8983
- container.appendChild(span);
8984
- container.appendChild(img);
8985
- const baseline = img.offsetTop - span.offsetTop + 2;
8986
- container.removeChild(span);
8987
- container.appendChild(this._document.createTextNode(SAMPLE_TEXT));
8988
- container.style.lineHeight = "normal";
8989
- img.style.verticalAlign = "super";
8990
- const middle = img.offsetTop - container.offsetTop + 2;
8991
- body.removeChild(container);
8992
- return {
8993
- baseline,
8994
- middle
8995
- };
8996
- }
8997
- getMetrics(fontFamily, fontSize) {
8998
- const key = `${fontFamily} ${fontSize}`;
8999
- if (typeof this._data[key] === "undefined") this._data[key] = this.parseMetrics(fontFamily, fontSize);
9000
- return this._data[key];
9001
- }
9002
- };
9003
- //#endregion
9004
8950
  //#region src/render/canvas/text/text-decoration-renderer.ts
9005
8951
  var TextDecorationRenderer = class {
9006
8952
  constructor(ctx) {
@@ -9089,6 +9035,33 @@ var TextDecorationRenderer = class {
9089
9035
  }
9090
9036
  };
9091
9037
  //#endregion
9038
+ //#region src/render/canvas/font-utils.ts
9039
+ /**
9040
+ * Font measurement utility
9041
+ *
9042
+ * Provides Canvas API-based baseline measurement that works correctly with
9043
+ * webfonts (which may not be loaded in the original document) and system fonts.
9044
+ *
9045
+ * Fallback chain:
9046
+ * 1. fontBoundingBoxAscent — font-level metric (Chrome 99+, FF 116+, Safari 17.4+)
9047
+ * 2. actualBoundingBoxAscent — glyph-level metric (widely supported)
9048
+ * 3. fallback value — coarse CSS fallback
9049
+ */
9050
+ const SAMPLE_TEXT = "Mg";
9051
+ /**
9052
+ * Measure the baseline ascent for the currently set font.
9053
+ *
9054
+ * @param ctx - Canvas 2D rendering context with ctx.font already set
9055
+ * @param fallback - Fallback value when no metrics are available (e.g. fontSize.number)
9056
+ * @returns The distance from the text baseline to the top of the bounding box
9057
+ */
9058
+ const measureBaseline = (ctx, fallback) => {
9059
+ const tm = ctx.measureText(SAMPLE_TEXT);
9060
+ const fmAscent = tm.fontBoundingBoxAscent;
9061
+ const ascent = fmAscent !== void 0 && !Number.isNaN(fmAscent) ? fmAscent : tm.actualBoundingBoxAscent;
9062
+ return ascent !== void 0 && !Number.isNaN(ascent) ? ascent : fallback;
9063
+ };
9064
+ //#endregion
9092
9065
  //#region src/render/canvas/text-renderer.ts
9093
9066
  const iOSBrokenFonts = ["-apple-system", "system-ui"];
9094
9067
  /**
@@ -9141,7 +9114,6 @@ var TextRenderer = class {
9141
9114
  constructor(deps) {
9142
9115
  this.glyphWidthCache = null;
9143
9116
  this.ctx = deps.ctx;
9144
- this.fontMetrics = deps.fontMetrics;
9145
9117
  this.options = deps.options;
9146
9118
  this.decorationRenderer = new TextDecorationRenderer(deps.ctx);
9147
9119
  }
@@ -9402,13 +9374,13 @@ var TextRenderer = class {
9402
9374
  }
9403
9375
  async renderTextNode(text, styles, containerBounds) {
9404
9376
  this.glyphWidthCache = null;
9405
- const [fontString, fontFamily, fontSize] = this.createFontStyle(styles);
9377
+ const [fontString] = this.createFontStyle(styles);
9406
9378
  this.ctx.font = fontString;
9407
9379
  this.ctx.direction = styles.direction === 1 ? "rtl" : "ltr";
9408
9380
  this.ctx.textAlign = "left";
9409
9381
  this.ctx.textBaseline = "alphabetic";
9410
9382
  const paintOrder = styles.paintOrder;
9411
- const { baseline } = this.fontMetrics.getMetrics(fontFamily, fontSize);
9383
+ const baseline = measureBaseline(this.ctx, styles.fontSize.number);
9412
9384
  if (styles.webkitLineClamp > 0 && (styles.display & 2) !== 0 && styles.overflowY === 1 && text.textBounds.length > 0) {
9413
9385
  if (this.renderLineClampedText(text, styles, paintOrder, baseline, containerBounds)) return;
9414
9386
  }
@@ -10304,7 +10276,7 @@ async function renderReplacedElements(ctx, context, options, iframeRendererFacto
10304
10276
  /**
10305
10277
  * Render form element content: checkbox, radio, text input.
10306
10278
  */
10307
- function renderFormElements(ctx, fontMetrics, textRenderer, pathFn, container, styles) {
10279
+ function renderFormElements(ctx, textRenderer, pathFn, container, styles) {
10308
10280
  if (container instanceof InputElementContainer) {
10309
10281
  const size = Math.min(container.bounds.width, container.bounds.height);
10310
10282
  if (container.type === "checkbox" && container.checked) {
@@ -10331,9 +10303,9 @@ function renderFormElements(ctx, fontMetrics, textRenderer, pathFn, container, s
10331
10303
  }
10332
10304
  }
10333
10305
  if (isTextInputElement(container) && container.value.length) {
10334
- const [font, fontFamily, fontSize] = textRenderer.createFontStyle(styles);
10335
- const { baseline } = fontMetrics.getMetrics(fontFamily, fontSize);
10306
+ const [font] = textRenderer.createFontStyle(styles);
10336
10307
  ctx.font = font;
10308
+ const baseline = measureBaseline(ctx, getAbsoluteValue(styles.fontSize, 0));
10337
10309
  ctx.fillStyle = container instanceof InputElementContainer && container.isPlaceholder ? asString(PLACEHOLDER_COLOR) : asString(styles.color);
10338
10310
  ctx.textBaseline = "alphabetic";
10339
10311
  ctx.textAlign = canvasTextAlign(container.styles.textAlign);
@@ -10431,7 +10403,6 @@ var CanvasRenderer = class CanvasRenderer {
10431
10403
  this.canvas.style.width = `${options.width}px`;
10432
10404
  this.canvas.style.height = `${options.height}px`;
10433
10405
  }
10434
- this.fontMetrics = new FontMetrics(document);
10435
10406
  this.ctx.scale(this.options.scale, this.options.scale);
10436
10407
  this.ctx.translate(-options.x, -options.y);
10437
10408
  this.ctx.textBaseline = "bottom";
@@ -10455,7 +10426,6 @@ var CanvasRenderer = class CanvasRenderer {
10455
10426
  this.effectsRenderer = new EffectsRenderer({ ctx: this.ctx }, { path: (paths) => this.path(paths) });
10456
10427
  this.textRenderer = new TextRenderer({
10457
10428
  ctx: this.ctx,
10458
- fontMetrics: this.fontMetrics,
10459
10429
  options: { scale: options.scale }
10460
10430
  });
10461
10431
  this.context.logger.debug(`Canvas renderer initialized (${options.width}x${options.height}) with scale ${options.scale}`);
@@ -10503,7 +10473,7 @@ var CanvasRenderer = class CanvasRenderer {
10503
10473
  width: this.options.width,
10504
10474
  height: this.options.height
10505
10475
  }, (ctx, opts) => new CanvasRenderer(ctx, opts), container, curves, styles, (c, cv, img) => this.renderReplacedElement(c, cv, img));
10506
- renderFormElements(this.ctx, this.fontMetrics, this.textRenderer, this.path.bind(this), container, styles);
10476
+ renderFormElements(this.ctx, this.textRenderer, this.path.bind(this), container, styles);
10507
10477
  await renderListMarker(this.ctx, this.context, this.textRenderer, paint, container, styles);
10508
10478
  }
10509
10479
  async renderStackContent(stack) {