html2canvas-pro 2.3.6 → 2.3.8

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.6 <https://yorickshan.github.io/html2canvas-pro/>
2
+ * html2canvas-pro 2.3.8 <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
  */
@@ -5167,6 +5167,23 @@
5167
5167
  }
5168
5168
  };
5169
5169
  //#endregion
5170
+ //#region src/css/property-descriptors/white-space.ts
5171
+ const whiteSpace = {
5172
+ name: "white-space",
5173
+ initialValue: "normal",
5174
+ prefix: false,
5175
+ type: 2,
5176
+ parse: (_context, value) => {
5177
+ switch (value) {
5178
+ case "pre": return "pre";
5179
+ case "nowrap": return "nowrap";
5180
+ case "pre-wrap": return "pre-wrap";
5181
+ case "pre-line": return "pre-line";
5182
+ default: return "normal";
5183
+ }
5184
+ }
5185
+ };
5186
+ //#endregion
5170
5187
  //#region src/css/property-descriptors/writing-mode.ts
5171
5188
  const isVerticalWritingMode = (writingMode) => writingMode !== 0;
5172
5189
  const isSidewaysWritingMode = (writingMode) => writingMode === 3 || writingMode === 4;
@@ -6607,6 +6624,11 @@
6607
6624
  wordBreak,
6608
6625
  "wordBreak"
6609
6626
  ],
6627
+ [
6628
+ "whiteSpace",
6629
+ whiteSpace,
6630
+ "whiteSpace"
6631
+ ],
6610
6632
  [
6611
6633
  "writingMode",
6612
6634
  writingMode,
@@ -7452,7 +7474,12 @@
7452
7474
  this.bounds = parseBounds(this.context, element);
7453
7475
  if (element.tagName === "FIELDSET") {
7454
7476
  const legend = element.querySelector(":scope > legend");
7455
- if (legend) this.legendBounds = parseBounds(this.context, legend);
7477
+ if (legend) {
7478
+ const legendBounds = parseBounds(this.context, legend);
7479
+ this.legendBounds = legendBounds;
7480
+ const borderBoxTop = legendBounds.top + legendBounds.height / 2 - this.styles.borderTopWidth / 2;
7481
+ this.bounds = new Bounds(this.bounds.left, borderBoxTop, this.bounds.width, this.bounds.height - (borderBoxTop - this.bounds.top));
7482
+ }
7456
7483
  }
7457
7484
  if (isDebugging(element, 4)) this.debugRender = true;
7458
7485
  }
@@ -10360,13 +10387,57 @@
10360
10387
  new Vector(bounds.left, bounds.top + bounds.height)
10361
10388
  ]);
10362
10389
  ctx.clip();
10363
- textRenderer.renderTextWithLetterSpacing(new TextBounds(container.value, textBounds), styles.letterSpacing, baseline, styles.writingMode);
10390
+ const lines = wrapTextToWidth(ctx, container.value, bounds.width, styles.whiteSpace === "pre" || styles.whiteSpace === "nowrap");
10391
+ const fontSizeValue = getAbsoluteValue(styles.fontSize, 0);
10392
+ const lineHeight = computeLineHeight(styles.lineHeight, fontSizeValue);
10393
+ lines.forEach((line, index) => {
10394
+ let lineX = textBounds.left;
10395
+ const lineWidth = ctx.measureText(line).width;
10396
+ switch (styles.textAlign) {
10397
+ case 1:
10398
+ lineX += (bounds.width - lineWidth) / 2;
10399
+ break;
10400
+ case 2:
10401
+ lineX += bounds.width - lineWidth;
10402
+ break;
10403
+ }
10404
+ const lineBounds = new Bounds(lineX, textBounds.top + index * lineHeight, 0, 0);
10405
+ textRenderer.renderTextWithLetterSpacing(new TextBounds(line, lineBounds), styles.letterSpacing, baseline, styles.writingMode);
10406
+ });
10364
10407
  ctx.restore();
10365
10408
  ctx.textBaseline = "alphabetic";
10366
10409
  ctx.textAlign = "left";
10367
10410
  }
10368
10411
  }
10369
10412
  /**
10413
+ * Split text into lines that fit the given pixel width, preserving hard line
10414
+ * breaks and (when wrapping is enabled) breaking at word boundaries — mirroring
10415
+ * how a <textarea> lays out its value.
10416
+ * @internal exported for testing
10417
+ */
10418
+ const wrapTextToWidth = (ctx, text, maxWidth, noWrap) => {
10419
+ const lines = [];
10420
+ const paragraphs = text.split("\n");
10421
+ for (const paragraph of paragraphs) {
10422
+ if (noWrap) {
10423
+ lines.push(paragraph);
10424
+ continue;
10425
+ }
10426
+ const words = paragraph.split(/(\s+)/);
10427
+ let line = "";
10428
+ for (const word of words) {
10429
+ const candidate = line + word;
10430
+ if (ctx.measureText(candidate).width <= maxWidth || line === "") line = candidate;
10431
+ else {
10432
+ lines.push(line);
10433
+ line = word;
10434
+ }
10435
+ }
10436
+ lines.push(line);
10437
+ }
10438
+ return lines;
10439
+ };
10440
+ /**
10370
10441
  * Render list-item marker (image or text).
10371
10442
  */
10372
10443
  async function renderListMarker(ctx, context, textRenderer, paint, container, styles) {
@@ -10964,7 +11035,8 @@
10964
11035
  const originChecker = this.context.originChecker;
10965
11036
  const defaultIsSameOrigin = (src) => originChecker.isSameOrigin(src);
10966
11037
  const isSameOrigin = typeof this._options.customIsSameOrigin === "function" ? await this._options.customIsSameOrigin(key, defaultIsSameOrigin) : defaultIsSameOrigin(key);
10967
- const useCORS = !isInlineImage(key) && this._options.useCORS === true && FEATURES.SUPPORT_CORS_IMAGES && !isSameOrigin;
11038
+ const canAttemptCors = !isSameOrigin && this._options.allowTaint === false && !isInlineImage(key) && !isBlobImage(key) && typeof this._options.proxy !== "string";
11039
+ const useCORS = !isInlineImage(key) && (this._options.useCORS === true || canAttemptCors) && FEATURES.SUPPORT_CORS_IMAGES && !isSameOrigin;
10968
11040
  const useProxy = !isInlineImage(key) && !isSameOrigin && !isBlobImage(key) && typeof this._options.proxy === "string" && FEATURES.SUPPORT_CORS_XHR && !useCORS;
10969
11041
  if (!isSameOrigin && this._options.allowTaint === false && !isInlineImage(key) && !isBlobImage(key) && !useProxy && !useCORS) return;
10970
11042
  let src = key;