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
  */
@@ -8943,60 +8943,6 @@ const calculateBackgroundRepeatPath = (repeat, [x, y], [width, height], backgrou
8943
8943
  }
8944
8944
  };
8945
8945
  //#endregion
8946
- //#region src/core/util.ts
8947
- const SMALL_IMAGE = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
8948
- //#endregion
8949
- //#region src/render/font-metrics.ts
8950
- const SAMPLE_TEXT = "Hidden Text";
8951
- var FontMetrics = class {
8952
- constructor(document) {
8953
- this._data = {};
8954
- this._document = document;
8955
- }
8956
- parseMetrics(fontFamily, fontSize) {
8957
- const container = this._document.createElement("div");
8958
- const img = this._document.createElement("img");
8959
- const span = this._document.createElement("span");
8960
- const body = this._document.body;
8961
- container.style.visibility = "hidden";
8962
- container.style.fontFamily = fontFamily;
8963
- container.style.fontSize = fontSize;
8964
- container.style.margin = "0";
8965
- container.style.padding = "0";
8966
- container.style.whiteSpace = "nowrap";
8967
- body.appendChild(container);
8968
- img.src = SMALL_IMAGE;
8969
- img.width = 1;
8970
- img.height = 1;
8971
- img.style.margin = "0";
8972
- img.style.padding = "0";
8973
- img.style.verticalAlign = "baseline";
8974
- span.style.fontFamily = fontFamily;
8975
- span.style.fontSize = fontSize;
8976
- span.style.margin = "0";
8977
- span.style.padding = "0";
8978
- span.appendChild(this._document.createTextNode(SAMPLE_TEXT));
8979
- container.appendChild(span);
8980
- container.appendChild(img);
8981
- const baseline = img.offsetTop - span.offsetTop + 2;
8982
- container.removeChild(span);
8983
- container.appendChild(this._document.createTextNode(SAMPLE_TEXT));
8984
- container.style.lineHeight = "normal";
8985
- img.style.verticalAlign = "super";
8986
- const middle = img.offsetTop - container.offsetTop + 2;
8987
- body.removeChild(container);
8988
- return {
8989
- baseline,
8990
- middle
8991
- };
8992
- }
8993
- getMetrics(fontFamily, fontSize) {
8994
- const key = `${fontFamily} ${fontSize}`;
8995
- if (typeof this._data[key] === "undefined") this._data[key] = this.parseMetrics(fontFamily, fontSize);
8996
- return this._data[key];
8997
- }
8998
- };
8999
- //#endregion
9000
8946
  //#region src/render/canvas/text/text-decoration-renderer.ts
9001
8947
  var TextDecorationRenderer = class {
9002
8948
  constructor(ctx) {
@@ -9085,6 +9031,33 @@ var TextDecorationRenderer = class {
9085
9031
  }
9086
9032
  };
9087
9033
  //#endregion
9034
+ //#region src/render/canvas/font-utils.ts
9035
+ /**
9036
+ * Font measurement utility
9037
+ *
9038
+ * Provides Canvas API-based baseline measurement that works correctly with
9039
+ * webfonts (which may not be loaded in the original document) and system fonts.
9040
+ *
9041
+ * Fallback chain:
9042
+ * 1. fontBoundingBoxAscent — font-level metric (Chrome 99+, FF 116+, Safari 17.4+)
9043
+ * 2. actualBoundingBoxAscent — glyph-level metric (widely supported)
9044
+ * 3. fallback value — coarse CSS fallback
9045
+ */
9046
+ const SAMPLE_TEXT = "Mg";
9047
+ /**
9048
+ * Measure the baseline ascent for the currently set font.
9049
+ *
9050
+ * @param ctx - Canvas 2D rendering context with ctx.font already set
9051
+ * @param fallback - Fallback value when no metrics are available (e.g. fontSize.number)
9052
+ * @returns The distance from the text baseline to the top of the bounding box
9053
+ */
9054
+ const measureBaseline = (ctx, fallback) => {
9055
+ const tm = ctx.measureText(SAMPLE_TEXT);
9056
+ const fmAscent = tm.fontBoundingBoxAscent;
9057
+ const ascent = fmAscent !== void 0 && !Number.isNaN(fmAscent) ? fmAscent : tm.actualBoundingBoxAscent;
9058
+ return ascent !== void 0 && !Number.isNaN(ascent) ? ascent : fallback;
9059
+ };
9060
+ //#endregion
9088
9061
  //#region src/render/canvas/text-renderer.ts
9089
9062
  const iOSBrokenFonts = ["-apple-system", "system-ui"];
9090
9063
  /**
@@ -9137,7 +9110,6 @@ var TextRenderer = class {
9137
9110
  constructor(deps) {
9138
9111
  this.glyphWidthCache = null;
9139
9112
  this.ctx = deps.ctx;
9140
- this.fontMetrics = deps.fontMetrics;
9141
9113
  this.options = deps.options;
9142
9114
  this.decorationRenderer = new TextDecorationRenderer(deps.ctx);
9143
9115
  }
@@ -9398,13 +9370,13 @@ var TextRenderer = class {
9398
9370
  }
9399
9371
  async renderTextNode(text, styles, containerBounds) {
9400
9372
  this.glyphWidthCache = null;
9401
- const [fontString, fontFamily, fontSize] = this.createFontStyle(styles);
9373
+ const [fontString] = this.createFontStyle(styles);
9402
9374
  this.ctx.font = fontString;
9403
9375
  this.ctx.direction = styles.direction === 1 ? "rtl" : "ltr";
9404
9376
  this.ctx.textAlign = "left";
9405
9377
  this.ctx.textBaseline = "alphabetic";
9406
9378
  const paintOrder = styles.paintOrder;
9407
- const { baseline } = this.fontMetrics.getMetrics(fontFamily, fontSize);
9379
+ const baseline = measureBaseline(this.ctx, styles.fontSize.number);
9408
9380
  if (styles.webkitLineClamp > 0 && (styles.display & 2) !== 0 && styles.overflowY === 1 && text.textBounds.length > 0) {
9409
9381
  if (this.renderLineClampedText(text, styles, paintOrder, baseline, containerBounds)) return;
9410
9382
  }
@@ -10300,7 +10272,7 @@ async function renderReplacedElements(ctx, context, options, iframeRendererFacto
10300
10272
  /**
10301
10273
  * Render form element content: checkbox, radio, text input.
10302
10274
  */
10303
- function renderFormElements(ctx, fontMetrics, textRenderer, pathFn, container, styles) {
10275
+ function renderFormElements(ctx, textRenderer, pathFn, container, styles) {
10304
10276
  if (container instanceof InputElementContainer) {
10305
10277
  const size = Math.min(container.bounds.width, container.bounds.height);
10306
10278
  if (container.type === "checkbox" && container.checked) {
@@ -10327,9 +10299,9 @@ function renderFormElements(ctx, fontMetrics, textRenderer, pathFn, container, s
10327
10299
  }
10328
10300
  }
10329
10301
  if (isTextInputElement(container) && container.value.length) {
10330
- const [font, fontFamily, fontSize] = textRenderer.createFontStyle(styles);
10331
- const { baseline } = fontMetrics.getMetrics(fontFamily, fontSize);
10302
+ const [font] = textRenderer.createFontStyle(styles);
10332
10303
  ctx.font = font;
10304
+ const baseline = measureBaseline(ctx, getAbsoluteValue(styles.fontSize, 0));
10333
10305
  ctx.fillStyle = container instanceof InputElementContainer && container.isPlaceholder ? asString(PLACEHOLDER_COLOR) : asString(styles.color);
10334
10306
  ctx.textBaseline = "alphabetic";
10335
10307
  ctx.textAlign = canvasTextAlign(container.styles.textAlign);
@@ -10427,7 +10399,6 @@ var CanvasRenderer = class CanvasRenderer {
10427
10399
  this.canvas.style.width = `${options.width}px`;
10428
10400
  this.canvas.style.height = `${options.height}px`;
10429
10401
  }
10430
- this.fontMetrics = new FontMetrics(document);
10431
10402
  this.ctx.scale(this.options.scale, this.options.scale);
10432
10403
  this.ctx.translate(-options.x, -options.y);
10433
10404
  this.ctx.textBaseline = "bottom";
@@ -10451,7 +10422,6 @@ var CanvasRenderer = class CanvasRenderer {
10451
10422
  this.effectsRenderer = new EffectsRenderer({ ctx: this.ctx }, { path: (paths) => this.path(paths) });
10452
10423
  this.textRenderer = new TextRenderer({
10453
10424
  ctx: this.ctx,
10454
- fontMetrics: this.fontMetrics,
10455
10425
  options: { scale: options.scale }
10456
10426
  });
10457
10427
  this.context.logger.debug(`Canvas renderer initialized (${options.width}x${options.height}) with scale ${options.scale}`);
@@ -10499,7 +10469,7 @@ var CanvasRenderer = class CanvasRenderer {
10499
10469
  width: this.options.width,
10500
10470
  height: this.options.height
10501
10471
  }, (ctx, opts) => new CanvasRenderer(ctx, opts), container, curves, styles, (c, cv, img) => this.renderReplacedElement(c, cv, img));
10502
- renderFormElements(this.ctx, this.fontMetrics, this.textRenderer, this.path.bind(this), container, styles);
10472
+ renderFormElements(this.ctx, this.textRenderer, this.path.bind(this), container, styles);
10503
10473
  await renderListMarker(this.ctx, this.context, this.textRenderer, paint, container, styles);
10504
10474
  }
10505
10475
  async renderStackContent(stack) {