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