html2canvas-pro 2.3.0 → 2.3.1

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.0 <https://yorickshan.github.io/html2canvas-pro/>
2
+ * html2canvas-pro 2.3.1 <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
  */
@@ -9137,6 +9137,7 @@ var TextRenderer = class {
9137
9137
  constructor(deps) {
9138
9138
  this.glyphWidthCache = null;
9139
9139
  this.ctx = deps.ctx;
9140
+ this.fontMetrics = deps.fontMetrics;
9140
9141
  this.options = deps.options;
9141
9142
  this.decorationRenderer = new TextDecorationRenderer(deps.ctx);
9142
9143
  }
@@ -9251,19 +9252,19 @@ var TextRenderer = class {
9251
9252
  this.ctx.strokeText(letter, x, y);
9252
9253
  });
9253
9254
  }
9254
- renderTextStrokeWithStyle(text, styles) {
9255
+ renderTextStrokeWithStyle(text, styles, baseline) {
9255
9256
  if (!styles.webkitTextStrokeWidth || !text.text.trim().length) return;
9256
9257
  this.ctx.strokeStyle = asString(styles.webkitTextStrokeColor);
9257
9258
  this.ctx.lineWidth = styles.webkitTextStrokeWidth;
9258
9259
  this.ctx.lineJoin = getTextStrokeLineJoin();
9259
- this.renderStrokeText(text, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
9260
+ this.renderStrokeText(text, styles.letterSpacing, baseline, styles.writingMode);
9260
9261
  this.ctx.strokeStyle = "";
9261
9262
  this.ctx.lineWidth = 0;
9262
9263
  this.ctx.lineJoin = "miter";
9263
9264
  }
9264
- renderTextFillWithShadows(text, styles) {
9265
+ renderTextFillWithShadows(text, styles, baseline) {
9265
9266
  this.ctx.fillStyle = asString(styles.color);
9266
- this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
9267
+ this.renderTextWithLetterSpacing(text, styles.letterSpacing, baseline, styles.writingMode);
9267
9268
  const textShadows = styles.textShadow;
9268
9269
  if (textShadows.length && text.text.trim().length) {
9269
9270
  textShadows.slice(0).reverse().forEach((textShadow) => {
@@ -9271,7 +9272,7 @@ var TextRenderer = class {
9271
9272
  this.ctx.shadowOffsetX = textShadow.offsetX.number * this.options.scale;
9272
9273
  this.ctx.shadowOffsetY = textShadow.offsetY.number * this.options.scale;
9273
9274
  this.ctx.shadowBlur = textShadow.blur.number;
9274
- this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
9275
+ this.renderTextWithLetterSpacing(text, styles.letterSpacing, baseline, styles.writingMode);
9275
9276
  });
9276
9277
  this.ctx.shadowColor = "";
9277
9278
  this.ctx.shadowOffsetX = 0;
@@ -9283,15 +9284,15 @@ var TextRenderer = class {
9283
9284
  * Helper method to render text with paint order support
9284
9285
  * Reduces code duplication in line-clamp and normal rendering
9285
9286
  */
9286
- renderTextBoundWithPaintOrder(textBound, styles, paintOrderLayers) {
9287
+ renderTextBoundWithPaintOrder(textBound, styles, paintOrderLayers, baseline) {
9287
9288
  paintOrderLayers.forEach((paintOrderLayer) => {
9288
9289
  switch (paintOrderLayer) {
9289
9290
  case 0:
9290
9291
  this.ctx.fillStyle = asString(styles.color);
9291
- this.renderTextWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
9292
+ this.renderTextWithLetterSpacing(textBound, styles.letterSpacing, baseline, styles.writingMode);
9292
9293
  break;
9293
9294
  case 1:
9294
- this.renderTextStrokeWithStyle(textBound, styles);
9295
+ this.renderTextStrokeWithStyle(textBound, styles, baseline);
9295
9296
  break;
9296
9297
  }
9297
9298
  });
@@ -9351,7 +9352,7 @@ var TextRenderer = class {
9351
9352
  * Groups text bounds by their Y position into visual lines, then renders
9352
9353
  * only the first N-1 complete lines followed by an ellipsis on the Nth line.
9353
9354
  */
9354
- renderLineClampedText(text, styles, paintOrder, containerBounds) {
9355
+ renderLineClampedText(text, styles, paintOrder, baseline, containerBounds) {
9355
9356
  const lineHeight = styles.fontSize.number * 1.5;
9356
9357
  const lines = [];
9357
9358
  let currentLine = [];
@@ -9366,7 +9367,7 @@ var TextRenderer = class {
9366
9367
  if (currentLine.length > 0) lines.push(currentLine);
9367
9368
  const maxLines = styles.webkitLineClamp;
9368
9369
  if (lines.length <= maxLines) return false;
9369
- for (let i = 0; i < maxLines - 1; i++) lines[i].forEach((tb) => this.renderTextBoundWithPaintOrder(tb, styles, paintOrder));
9370
+ for (let i = 0; i < maxLines - 1; i++) lines[i].forEach((tb) => this.renderTextBoundWithPaintOrder(tb, styles, paintOrder, baseline));
9370
9371
  const lastLine = lines[maxLines - 1];
9371
9372
  if (lastLine?.length && containerBounds) {
9372
9373
  const textStr = lastLine.map((tb) => tb.text).join("");
@@ -9375,8 +9376,8 @@ var TextRenderer = class {
9375
9376
  const bounds = new TextBounds(this.truncateTextWithEllipsis(textStr, avail, styles.letterSpacing), first.bounds);
9376
9377
  for (const layer of paintOrder) if (layer === 0) {
9377
9378
  this.ctx.fillStyle = asString(styles.color);
9378
- this.renderTextWithLetterSpacing(bounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
9379
- } else if (layer === 1) this.renderTextStrokeWithStyle(bounds, styles);
9379
+ this.renderTextWithLetterSpacing(bounds, styles.letterSpacing, baseline, styles.writingMode);
9380
+ } else if (layer === 1) this.renderTextStrokeWithStyle(bounds, styles, baseline);
9380
9381
  }
9381
9382
  return true;
9382
9383
  }
@@ -9384,34 +9385,36 @@ var TextRenderer = class {
9384
9385
  * Render single-line text with text-overflow: ellipsis.
9385
9386
  * Returns true if ellipsis was applied (caller should skip normal rendering).
9386
9387
  */
9387
- renderEllipsisText(text, styles, paintOrder, containerBounds) {
9388
+ renderEllipsisText(text, styles, paintOrder, baseline, containerBounds) {
9388
9389
  const lineHeight = styles.fontSize.number * 1.5;
9389
9390
  const firstTop = text.textBounds[0].bounds.top;
9390
9391
  if (!text.textBounds.every((tb) => Math.abs(tb.bounds.top - firstTop) < lineHeight * .5)) return false;
9391
9392
  let fullText = text.textBounds.map((tb) => tb.text).join("").replace(/\s+/g, " ").trim();
9392
9393
  if (this.ctx.measureText(fullText).width <= containerBounds.width) return false;
9393
9394
  const bounds = new TextBounds(this.truncateTextWithEllipsis(fullText, containerBounds.width, styles.letterSpacing), text.textBounds[0].bounds);
9394
- for (const layer of paintOrder) if (layer === 0) this.renderTextFillWithShadows(bounds, styles);
9395
- else if (layer === 1) this.renderTextStrokeWithStyle(bounds, styles);
9395
+ for (const layer of paintOrder) if (layer === 0) this.renderTextFillWithShadows(bounds, styles, baseline);
9396
+ else if (layer === 1) this.renderTextStrokeWithStyle(bounds, styles, baseline);
9396
9397
  return true;
9397
9398
  }
9398
9399
  async renderTextNode(text, styles, containerBounds) {
9399
9400
  this.glyphWidthCache = null;
9400
- this.ctx.font = this.createFontStyle(styles)[0];
9401
+ const [fontString, fontFamily, fontSize] = this.createFontStyle(styles);
9402
+ this.ctx.font = fontString;
9401
9403
  this.ctx.direction = styles.direction === 1 ? "rtl" : "ltr";
9402
9404
  this.ctx.textAlign = "left";
9403
9405
  this.ctx.textBaseline = "alphabetic";
9404
9406
  const paintOrder = styles.paintOrder;
9407
+ const { baseline } = this.fontMetrics.getMetrics(fontFamily, fontSize);
9405
9408
  if (styles.webkitLineClamp > 0 && (styles.display & 2) !== 0 && styles.overflowY === 1 && text.textBounds.length > 0) {
9406
- if (this.renderLineClampedText(text, styles, paintOrder, containerBounds)) return;
9409
+ if (this.renderLineClampedText(text, styles, paintOrder, baseline, containerBounds)) return;
9407
9410
  }
9408
- if (styles.textOverflow === 1 && containerBounds && styles.overflowX === 1 && text.textBounds.length > 0 && this.renderEllipsisText(text, styles, paintOrder, containerBounds)) return;
9411
+ if (styles.textOverflow === 1 && containerBounds && styles.overflowX === 1 && text.textBounds.length > 0 && this.renderEllipsisText(text, styles, paintOrder, baseline, containerBounds)) return;
9409
9412
  text.textBounds.forEach((tb) => {
9410
9413
  paintOrder.forEach((layer) => {
9411
9414
  if (layer === 0) {
9412
- this.renderTextFillWithShadows(tb, styles);
9415
+ this.renderTextFillWithShadows(tb, styles, baseline);
9413
9416
  if (styles.textDecorationLine.length) this.renderTextDecoration(tb.bounds, styles);
9414
- } else if (layer === 1) this.renderTextStrokeWithStyle(tb, styles);
9417
+ } else if (layer === 1) this.renderTextStrokeWithStyle(tb, styles, baseline);
9415
9418
  });
9416
9419
  });
9417
9420
  }
@@ -10448,7 +10451,7 @@ var CanvasRenderer = class CanvasRenderer {
10448
10451
  this.effectsRenderer = new EffectsRenderer({ ctx: this.ctx }, { path: (paths) => this.path(paths) });
10449
10452
  this.textRenderer = new TextRenderer({
10450
10453
  ctx: this.ctx,
10451
- context: this.context,
10454
+ fontMetrics: this.fontMetrics,
10452
10455
  options: { scale: options.scale }
10453
10456
  });
10454
10457
  this.context.logger.debug(`Canvas renderer initialized (${options.width}x${options.height}) with scale ${options.scale}`);