html2canvas-pro 2.0.3 → 2.0.4

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.0.3 <https://yorickshan.github.io/html2canvas-pro/>
2
+ * html2canvas-pro 2.0.4 <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
  */
@@ -4245,6 +4245,30 @@
4245
4245
  }
4246
4246
  };
4247
4247
 
4248
+ const isVerticalWritingMode = (writingMode) => writingMode !== 0 /* WRITING_MODE.HORIZONTAL_TB */;
4249
+ const isSidewaysWritingMode = (writingMode) => writingMode === 3 /* WRITING_MODE.SIDEWAYS_RL */ || writingMode === 4 /* WRITING_MODE.SIDEWAYS_LR */;
4250
+ const writingMode = {
4251
+ name: 'writing-mode',
4252
+ initialValue: 'horizontal-tb',
4253
+ prefix: false,
4254
+ type: 2 /* PropertyDescriptorParsingType.IDENT_VALUE */,
4255
+ parse: (_context, writingMode) => {
4256
+ switch (writingMode) {
4257
+ case 'vertical-rl':
4258
+ return 1 /* WRITING_MODE.VERTICAL_RL */;
4259
+ case 'vertical-lr':
4260
+ return 2 /* WRITING_MODE.VERTICAL_LR */;
4261
+ case 'sideways-rl':
4262
+ return 3 /* WRITING_MODE.SIDEWAYS_RL */;
4263
+ case 'sideways-lr':
4264
+ return 4 /* WRITING_MODE.SIDEWAYS_LR */;
4265
+ case 'horizontal-tb':
4266
+ default:
4267
+ return 0 /* WRITING_MODE.HORIZONTAL_TB */;
4268
+ }
4269
+ }
4270
+ };
4271
+
4248
4272
  const zIndex = {
4249
4273
  name: 'z-index',
4250
4274
  initialValue: 'auto',
@@ -4861,6 +4885,7 @@
4861
4885
  this.webkitTextStrokeWidth = parse(context, webkitTextStrokeWidth, declaration.webkitTextStrokeWidth);
4862
4886
  this.webkitLineClamp = parse(context, webkitLineClamp, declaration.webkitLineClamp);
4863
4887
  this.wordBreak = parse(context, wordBreak, declaration.wordBreak);
4888
+ this.writingMode = parse(context, writingMode, declaration.writingMode);
4864
4889
  this.zIndex = parse(context, zIndex, declaration.zIndex);
4865
4890
  this.objectFit = parse(context, objectFit, declaration.objectFit);
4866
4891
  this.imageRendering = parse(context, imageRendering, declaration.imageRendering);
@@ -5796,6 +5821,9 @@
5796
5821
  return breakWords(value, styles);
5797
5822
  };
5798
5823
  const breakText = (value, styles) => {
5824
+ if (isVerticalWritingMode(styles.writingMode)) {
5825
+ return segmentGraphemes(value);
5826
+ }
5799
5827
  return styles.letterSpacing !== 0 ? segmentGraphemes(value) : segmentWords(value, styles);
5800
5828
  };
5801
5829
  // https://drafts.csswg.org/css-text/#word-separator
@@ -5835,6 +5863,11 @@
5835
5863
  class TextContainer {
5836
5864
  constructor(context, node, styles) {
5837
5865
  this.text = transform(node.data, styles.textTransform);
5866
+ // Range offsets below are based on transformed text; keep the node in sync
5867
+ // when casing changes string length, for example "ß".toUpperCase() === "SS".
5868
+ if (this.text.length !== node.data.length) {
5869
+ node.data = this.text;
5870
+ }
5838
5871
  this.textBounds = parseTextBounds(context, this.text, styles, node);
5839
5872
  }
5840
5873
  }
@@ -8723,7 +8756,11 @@
8723
8756
  * call (fillText or strokeText), allowing fill and stroke paths to share one
8724
8757
  * implementation.
8725
8758
  */
8726
- iterateLettersWithLetterSpacing(text, letterSpacing, baseline, renderFn) {
8759
+ iterateLettersWithLetterSpacing(text, letterSpacing, baseline, writingMode, renderFn) {
8760
+ if (isVerticalWritingMode(writingMode)) {
8761
+ this.iterateVerticalGlyphs(text, letterSpacing, baseline, writingMode, renderFn);
8762
+ return;
8763
+ }
8727
8764
  const letters = segmentGraphemes(text.text);
8728
8765
  const y = text.bounds.top + baseline;
8729
8766
  let left = text.bounds.left;
@@ -8740,17 +8777,39 @@
8740
8777
  left += this.ctx.measureText(letter).width + letterSpacing;
8741
8778
  }
8742
8779
  }
8780
+ iterateVerticalGlyphs(text, letterSpacing, baseline, writingMode, renderFn) {
8781
+ const letters = segmentGraphemes(text.text);
8782
+ let top = text.bounds.top;
8783
+ for (const letter of letters) {
8784
+ if (isSidewaysWritingMode(writingMode) || (!hasCJKCharacters(letter) && letter.trim().length > 0)) {
8785
+ this.ctx.save();
8786
+ this.ctx.translate(text.bounds.left + baseline, top);
8787
+ this.ctx.rotate(writingMode === 4 /* WRITING_MODE.SIDEWAYS_LR */ ? -Math.PI / 2 : Math.PI / 2);
8788
+ renderFn(letter, 0, 0);
8789
+ this.ctx.restore();
8790
+ }
8791
+ else {
8792
+ const savedBaseline = this.ctx.textBaseline;
8793
+ if (hasCJKCharacters(letter)) {
8794
+ this.ctx.textBaseline = 'ideographic';
8795
+ }
8796
+ renderFn(letter, text.bounds.left, top + baseline);
8797
+ this.ctx.textBaseline = savedBaseline;
8798
+ }
8799
+ top += this.ctx.measureText(letter).width + letterSpacing;
8800
+ }
8801
+ }
8743
8802
  /**
8744
8803
  * Render text with letter-spacing applied (fill pass).
8745
8804
  * When letterSpacing is 0 the whole string is drawn in one call; otherwise each
8746
8805
  * grapheme is drawn individually so spacing and CJK baseline are applied correctly.
8747
8806
  */
8748
- renderTextWithLetterSpacing(text, letterSpacing, baseline) {
8749
- if (letterSpacing === 0) {
8807
+ renderTextWithLetterSpacing(text, letterSpacing, baseline, writingMode = 0 /* WRITING_MODE.HORIZONTAL_TB */) {
8808
+ if (letterSpacing === 0 && !isVerticalWritingMode(writingMode)) {
8750
8809
  this.ctx.fillText(text.text, text.bounds.left, text.bounds.top + baseline);
8751
8810
  }
8752
8811
  else {
8753
- this.iterateLettersWithLetterSpacing(text, letterSpacing, baseline, (letter, x, y) => {
8812
+ this.iterateLettersWithLetterSpacing(text, letterSpacing, baseline, writingMode, (letter, x, y) => {
8754
8813
  this.ctx.fillText(letter, x, y);
8755
8814
  });
8756
8815
  }
@@ -8764,7 +8823,7 @@
8764
8823
  switch (paintOrderLayer) {
8765
8824
  case 0 /* PAINT_ORDER_LAYER.FILL */:
8766
8825
  this.ctx.fillStyle = asString(styles.color);
8767
- this.renderTextWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number);
8826
+ this.renderTextWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
8768
8827
  break;
8769
8828
  case 1 /* PAINT_ORDER_LAYER.STROKE */:
8770
8829
  if (styles.webkitTextStrokeWidth && textBound.text.trim().length) {
@@ -8772,11 +8831,11 @@
8772
8831
  this.ctx.lineWidth = styles.webkitTextStrokeWidth;
8773
8832
  this.ctx.lineJoin =
8774
8833
  typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
8775
- if (styles.letterSpacing === 0) {
8834
+ if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
8776
8835
  this.ctx.strokeText(textBound.text, textBound.bounds.left, textBound.bounds.top + styles.fontSize.number);
8777
8836
  }
8778
8837
  else {
8779
- this.iterateLettersWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.strokeText(letter, x, y));
8838
+ this.iterateLettersWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
8780
8839
  }
8781
8840
  this.ctx.strokeStyle = '';
8782
8841
  this.ctx.lineWidth = 0;
@@ -9012,11 +9071,11 @@
9012
9071
  switch (paintOrderLayer) {
9013
9072
  case 0 /* PAINT_ORDER_LAYER.FILL */:
9014
9073
  this.ctx.fillStyle = asString(styles.color);
9015
- if (styles.letterSpacing === 0) {
9074
+ if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
9016
9075
  this.ctx.fillText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
9017
9076
  }
9018
9077
  else {
9019
- this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.fillText(letter, x, y));
9078
+ this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.fillText(letter, x, y));
9020
9079
  }
9021
9080
  break;
9022
9081
  case 1 /* PAINT_ORDER_LAYER.STROKE */:
@@ -9025,11 +9084,11 @@
9025
9084
  this.ctx.lineWidth = styles.webkitTextStrokeWidth;
9026
9085
  this.ctx.lineJoin =
9027
9086
  typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
9028
- if (styles.letterSpacing === 0) {
9087
+ if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
9029
9088
  this.ctx.strokeText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
9030
9089
  }
9031
9090
  else {
9032
- this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.strokeText(letter, x, y));
9091
+ this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
9033
9092
  }
9034
9093
  this.ctx.strokeStyle = '';
9035
9094
  this.ctx.lineWidth = 0;
@@ -9084,11 +9143,11 @@
9084
9143
  switch (paintOrderLayer) {
9085
9144
  case 0 /* PAINT_ORDER_LAYER.FILL */: {
9086
9145
  this.ctx.fillStyle = asString(styles.color);
9087
- if (styles.letterSpacing === 0) {
9146
+ if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
9088
9147
  this.ctx.fillText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
9089
9148
  }
9090
9149
  else {
9091
- this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.fillText(letter, x, y));
9150
+ this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.fillText(letter, x, y));
9092
9151
  }
9093
9152
  const textShadows = styles.textShadow;
9094
9153
  if (textShadows.length && truncatedText.trim().length) {
@@ -9100,11 +9159,11 @@
9100
9159
  this.ctx.shadowOffsetX = textShadow.offsetX.number * this.options.scale;
9101
9160
  this.ctx.shadowOffsetY = textShadow.offsetY.number * this.options.scale;
9102
9161
  this.ctx.shadowBlur = textShadow.blur.number;
9103
- if (styles.letterSpacing === 0) {
9162
+ if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
9104
9163
  this.ctx.fillText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
9105
9164
  }
9106
9165
  else {
9107
- this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.fillText(letter, x, y));
9166
+ this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.fillText(letter, x, y));
9108
9167
  }
9109
9168
  });
9110
9169
  this.ctx.shadowColor = '';
@@ -9120,11 +9179,11 @@
9120
9179
  this.ctx.lineWidth = styles.webkitTextStrokeWidth;
9121
9180
  this.ctx.lineJoin =
9122
9181
  typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
9123
- if (styles.letterSpacing === 0) {
9182
+ if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
9124
9183
  this.ctx.strokeText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
9125
9184
  }
9126
9185
  else {
9127
- this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.strokeText(letter, x, y));
9186
+ this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
9128
9187
  }
9129
9188
  this.ctx.strokeStyle = '';
9130
9189
  this.ctx.lineWidth = 0;
@@ -9141,7 +9200,7 @@
9141
9200
  switch (paintOrderLayer) {
9142
9201
  case 0 /* PAINT_ORDER_LAYER.FILL */: {
9143
9202
  this.ctx.fillStyle = asString(styles.color);
9144
- this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number);
9203
+ this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
9145
9204
  const textShadows = styles.textShadow;
9146
9205
  if (textShadows.length && text.text.trim().length) {
9147
9206
  textShadows
@@ -9152,7 +9211,7 @@
9152
9211
  this.ctx.shadowOffsetX = textShadow.offsetX.number * this.options.scale;
9153
9212
  this.ctx.shadowOffsetY = textShadow.offsetY.number * this.options.scale;
9154
9213
  this.ctx.shadowBlur = textShadow.blur.number;
9155
- this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number);
9214
+ this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
9156
9215
  });
9157
9216
  this.ctx.shadowColor = '';
9158
9217
  this.ctx.shadowOffsetX = 0;
@@ -9171,11 +9230,11 @@
9171
9230
  this.ctx.lineJoin =
9172
9231
  typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
9173
9232
  const baseline = styles.fontSize.number;
9174
- if (styles.letterSpacing === 0) {
9233
+ if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
9175
9234
  this.ctx.strokeText(text.text, text.bounds.left, text.bounds.top + baseline);
9176
9235
  }
9177
9236
  else {
9178
- this.iterateLettersWithLetterSpacing(text, styles.letterSpacing, baseline, (letter, x, y) => this.ctx.strokeText(letter, x, y));
9237
+ this.iterateLettersWithLetterSpacing(text, styles.letterSpacing, baseline, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
9179
9238
  }
9180
9239
  this.ctx.strokeStyle = '';
9181
9240
  this.ctx.lineWidth = 0;
@@ -9470,7 +9529,7 @@
9470
9529
  new Vector(bounds.left, bounds.top + bounds.height)
9471
9530
  ]);
9472
9531
  this.ctx.clip();
9473
- this.textRenderer.renderTextWithLetterSpacing(new TextBounds(container.value, textBounds), styles.letterSpacing, baseline);
9532
+ this.textRenderer.renderTextWithLetterSpacing(new TextBounds(container.value, textBounds), styles.letterSpacing, baseline, styles.writingMode);
9474
9533
  this.ctx.restore();
9475
9534
  this.ctx.textBaseline = 'alphabetic';
9476
9535
  this.ctx.textAlign = 'left';
@@ -9497,7 +9556,7 @@
9497
9556
  this.ctx.textBaseline = 'middle';
9498
9557
  this.ctx.textAlign = 'right';
9499
9558
  const bounds = new Bounds(container.bounds.left, container.bounds.top + getAbsoluteValue(container.styles.paddingTop, container.bounds.width), container.bounds.width, computeLineHeight(styles.lineHeight, styles.fontSize.number) / 2 + 1);
9500
- this.textRenderer.renderTextWithLetterSpacing(new TextBounds(paint.listValue, bounds), styles.letterSpacing, computeLineHeight(styles.lineHeight, styles.fontSize.number) / 2 + 2);
9559
+ this.textRenderer.renderTextWithLetterSpacing(new TextBounds(paint.listValue, bounds), styles.letterSpacing, computeLineHeight(styles.lineHeight, styles.fontSize.number) / 2 + 2, styles.writingMode);
9501
9560
  this.ctx.textBaseline = 'bottom';
9502
9561
  this.ctx.textAlign = 'left';
9503
9562
  }