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.
- package/dist/html2canvas-pro.esm.js +83 -24
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +83 -24
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +5 -5
- package/dist/lib/css/index.js +2 -0
- package/dist/lib/css/index.js.map +1 -1
- package/dist/lib/css/layout/text.js +4 -0
- package/dist/lib/css/layout/text.js.map +1 -1
- package/dist/lib/css/property-descriptors/writing-mode.js +29 -0
- package/dist/lib/css/property-descriptors/writing-mode.js.map +1 -0
- package/dist/lib/dom/text-container.js +5 -0
- package/dist/lib/dom/text-container.js.map +1 -1
- package/dist/lib/render/canvas/__tests__/text-renderer.test.js +92 -0
- package/dist/lib/render/canvas/__tests__/text-renderer.test.js.map +1 -1
- package/dist/lib/render/canvas/canvas-renderer.js +2 -2
- package/dist/lib/render/canvas/canvas-renderer.js.map +1 -1
- package/dist/lib/render/canvas/text-renderer.js +48 -21
- package/dist/lib/render/canvas/text-renderer.js.map +1 -1
- package/dist/types/css/index.d.ts +2 -0
- package/dist/types/css/property-descriptors/writing-mode.d.ts +11 -0
- package/dist/types/render/canvas/text-renderer.d.ts +3 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* html2canvas-pro 2.0.
|
|
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
|
*/
|
|
@@ -4239,6 +4239,30 @@ const wordBreak = {
|
|
|
4239
4239
|
}
|
|
4240
4240
|
};
|
|
4241
4241
|
|
|
4242
|
+
const isVerticalWritingMode = (writingMode) => writingMode !== 0 /* WRITING_MODE.HORIZONTAL_TB */;
|
|
4243
|
+
const isSidewaysWritingMode = (writingMode) => writingMode === 3 /* WRITING_MODE.SIDEWAYS_RL */ || writingMode === 4 /* WRITING_MODE.SIDEWAYS_LR */;
|
|
4244
|
+
const writingMode = {
|
|
4245
|
+
name: 'writing-mode',
|
|
4246
|
+
initialValue: 'horizontal-tb',
|
|
4247
|
+
prefix: false,
|
|
4248
|
+
type: 2 /* PropertyDescriptorParsingType.IDENT_VALUE */,
|
|
4249
|
+
parse: (_context, writingMode) => {
|
|
4250
|
+
switch (writingMode) {
|
|
4251
|
+
case 'vertical-rl':
|
|
4252
|
+
return 1 /* WRITING_MODE.VERTICAL_RL */;
|
|
4253
|
+
case 'vertical-lr':
|
|
4254
|
+
return 2 /* WRITING_MODE.VERTICAL_LR */;
|
|
4255
|
+
case 'sideways-rl':
|
|
4256
|
+
return 3 /* WRITING_MODE.SIDEWAYS_RL */;
|
|
4257
|
+
case 'sideways-lr':
|
|
4258
|
+
return 4 /* WRITING_MODE.SIDEWAYS_LR */;
|
|
4259
|
+
case 'horizontal-tb':
|
|
4260
|
+
default:
|
|
4261
|
+
return 0 /* WRITING_MODE.HORIZONTAL_TB */;
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
};
|
|
4265
|
+
|
|
4242
4266
|
const zIndex = {
|
|
4243
4267
|
name: 'z-index',
|
|
4244
4268
|
initialValue: 'auto',
|
|
@@ -4855,6 +4879,7 @@ class CSSParsedDeclaration {
|
|
|
4855
4879
|
this.webkitTextStrokeWidth = parse(context, webkitTextStrokeWidth, declaration.webkitTextStrokeWidth);
|
|
4856
4880
|
this.webkitLineClamp = parse(context, webkitLineClamp, declaration.webkitLineClamp);
|
|
4857
4881
|
this.wordBreak = parse(context, wordBreak, declaration.wordBreak);
|
|
4882
|
+
this.writingMode = parse(context, writingMode, declaration.writingMode);
|
|
4858
4883
|
this.zIndex = parse(context, zIndex, declaration.zIndex);
|
|
4859
4884
|
this.objectFit = parse(context, objectFit, declaration.objectFit);
|
|
4860
4885
|
this.imageRendering = parse(context, imageRendering, declaration.imageRendering);
|
|
@@ -5790,6 +5815,9 @@ const segmentWords = (value, styles) => {
|
|
|
5790
5815
|
return breakWords(value, styles);
|
|
5791
5816
|
};
|
|
5792
5817
|
const breakText = (value, styles) => {
|
|
5818
|
+
if (isVerticalWritingMode(styles.writingMode)) {
|
|
5819
|
+
return segmentGraphemes(value);
|
|
5820
|
+
}
|
|
5793
5821
|
return styles.letterSpacing !== 0 ? segmentGraphemes(value) : segmentWords(value, styles);
|
|
5794
5822
|
};
|
|
5795
5823
|
// https://drafts.csswg.org/css-text/#word-separator
|
|
@@ -5829,6 +5857,11 @@ const breakWords = (str, styles) => {
|
|
|
5829
5857
|
class TextContainer {
|
|
5830
5858
|
constructor(context, node, styles) {
|
|
5831
5859
|
this.text = transform(node.data, styles.textTransform);
|
|
5860
|
+
// Range offsets below are based on transformed text; keep the node in sync
|
|
5861
|
+
// when casing changes string length, for example "ß".toUpperCase() === "SS".
|
|
5862
|
+
if (this.text.length !== node.data.length) {
|
|
5863
|
+
node.data = this.text;
|
|
5864
|
+
}
|
|
5832
5865
|
this.textBounds = parseTextBounds(context, this.text, styles, node);
|
|
5833
5866
|
}
|
|
5834
5867
|
}
|
|
@@ -8717,7 +8750,11 @@ class TextRenderer {
|
|
|
8717
8750
|
* call (fillText or strokeText), allowing fill and stroke paths to share one
|
|
8718
8751
|
* implementation.
|
|
8719
8752
|
*/
|
|
8720
|
-
iterateLettersWithLetterSpacing(text, letterSpacing, baseline, renderFn) {
|
|
8753
|
+
iterateLettersWithLetterSpacing(text, letterSpacing, baseline, writingMode, renderFn) {
|
|
8754
|
+
if (isVerticalWritingMode(writingMode)) {
|
|
8755
|
+
this.iterateVerticalGlyphs(text, letterSpacing, baseline, writingMode, renderFn);
|
|
8756
|
+
return;
|
|
8757
|
+
}
|
|
8721
8758
|
const letters = segmentGraphemes(text.text);
|
|
8722
8759
|
const y = text.bounds.top + baseline;
|
|
8723
8760
|
let left = text.bounds.left;
|
|
@@ -8734,17 +8771,39 @@ class TextRenderer {
|
|
|
8734
8771
|
left += this.ctx.measureText(letter).width + letterSpacing;
|
|
8735
8772
|
}
|
|
8736
8773
|
}
|
|
8774
|
+
iterateVerticalGlyphs(text, letterSpacing, baseline, writingMode, renderFn) {
|
|
8775
|
+
const letters = segmentGraphemes(text.text);
|
|
8776
|
+
let top = text.bounds.top;
|
|
8777
|
+
for (const letter of letters) {
|
|
8778
|
+
if (isSidewaysWritingMode(writingMode) || (!hasCJKCharacters(letter) && letter.trim().length > 0)) {
|
|
8779
|
+
this.ctx.save();
|
|
8780
|
+
this.ctx.translate(text.bounds.left + baseline, top);
|
|
8781
|
+
this.ctx.rotate(writingMode === 4 /* WRITING_MODE.SIDEWAYS_LR */ ? -Math.PI / 2 : Math.PI / 2);
|
|
8782
|
+
renderFn(letter, 0, 0);
|
|
8783
|
+
this.ctx.restore();
|
|
8784
|
+
}
|
|
8785
|
+
else {
|
|
8786
|
+
const savedBaseline = this.ctx.textBaseline;
|
|
8787
|
+
if (hasCJKCharacters(letter)) {
|
|
8788
|
+
this.ctx.textBaseline = 'ideographic';
|
|
8789
|
+
}
|
|
8790
|
+
renderFn(letter, text.bounds.left, top + baseline);
|
|
8791
|
+
this.ctx.textBaseline = savedBaseline;
|
|
8792
|
+
}
|
|
8793
|
+
top += this.ctx.measureText(letter).width + letterSpacing;
|
|
8794
|
+
}
|
|
8795
|
+
}
|
|
8737
8796
|
/**
|
|
8738
8797
|
* Render text with letter-spacing applied (fill pass).
|
|
8739
8798
|
* When letterSpacing is 0 the whole string is drawn in one call; otherwise each
|
|
8740
8799
|
* grapheme is drawn individually so spacing and CJK baseline are applied correctly.
|
|
8741
8800
|
*/
|
|
8742
|
-
renderTextWithLetterSpacing(text, letterSpacing, baseline) {
|
|
8743
|
-
if (letterSpacing === 0) {
|
|
8801
|
+
renderTextWithLetterSpacing(text, letterSpacing, baseline, writingMode = 0 /* WRITING_MODE.HORIZONTAL_TB */) {
|
|
8802
|
+
if (letterSpacing === 0 && !isVerticalWritingMode(writingMode)) {
|
|
8744
8803
|
this.ctx.fillText(text.text, text.bounds.left, text.bounds.top + baseline);
|
|
8745
8804
|
}
|
|
8746
8805
|
else {
|
|
8747
|
-
this.iterateLettersWithLetterSpacing(text, letterSpacing, baseline, (letter, x, y) => {
|
|
8806
|
+
this.iterateLettersWithLetterSpacing(text, letterSpacing, baseline, writingMode, (letter, x, y) => {
|
|
8748
8807
|
this.ctx.fillText(letter, x, y);
|
|
8749
8808
|
});
|
|
8750
8809
|
}
|
|
@@ -8758,7 +8817,7 @@ class TextRenderer {
|
|
|
8758
8817
|
switch (paintOrderLayer) {
|
|
8759
8818
|
case 0 /* PAINT_ORDER_LAYER.FILL */:
|
|
8760
8819
|
this.ctx.fillStyle = asString(styles.color);
|
|
8761
|
-
this.renderTextWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number);
|
|
8820
|
+
this.renderTextWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
|
|
8762
8821
|
break;
|
|
8763
8822
|
case 1 /* PAINT_ORDER_LAYER.STROKE */:
|
|
8764
8823
|
if (styles.webkitTextStrokeWidth && textBound.text.trim().length) {
|
|
@@ -8766,11 +8825,11 @@ class TextRenderer {
|
|
|
8766
8825
|
this.ctx.lineWidth = styles.webkitTextStrokeWidth;
|
|
8767
8826
|
this.ctx.lineJoin =
|
|
8768
8827
|
typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
|
|
8769
|
-
if (styles.letterSpacing === 0) {
|
|
8828
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
8770
8829
|
this.ctx.strokeText(textBound.text, textBound.bounds.left, textBound.bounds.top + styles.fontSize.number);
|
|
8771
8830
|
}
|
|
8772
8831
|
else {
|
|
8773
|
-
this.iterateLettersWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
8832
|
+
this.iterateLettersWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
8774
8833
|
}
|
|
8775
8834
|
this.ctx.strokeStyle = '';
|
|
8776
8835
|
this.ctx.lineWidth = 0;
|
|
@@ -9006,11 +9065,11 @@ class TextRenderer {
|
|
|
9006
9065
|
switch (paintOrderLayer) {
|
|
9007
9066
|
case 0 /* PAINT_ORDER_LAYER.FILL */:
|
|
9008
9067
|
this.ctx.fillStyle = asString(styles.color);
|
|
9009
|
-
if (styles.letterSpacing === 0) {
|
|
9068
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9010
9069
|
this.ctx.fillText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
|
|
9011
9070
|
}
|
|
9012
9071
|
else {
|
|
9013
|
-
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9072
|
+
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9014
9073
|
}
|
|
9015
9074
|
break;
|
|
9016
9075
|
case 1 /* PAINT_ORDER_LAYER.STROKE */:
|
|
@@ -9019,11 +9078,11 @@ class TextRenderer {
|
|
|
9019
9078
|
this.ctx.lineWidth = styles.webkitTextStrokeWidth;
|
|
9020
9079
|
this.ctx.lineJoin =
|
|
9021
9080
|
typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
|
|
9022
|
-
if (styles.letterSpacing === 0) {
|
|
9081
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9023
9082
|
this.ctx.strokeText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
|
|
9024
9083
|
}
|
|
9025
9084
|
else {
|
|
9026
|
-
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9085
|
+
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9027
9086
|
}
|
|
9028
9087
|
this.ctx.strokeStyle = '';
|
|
9029
9088
|
this.ctx.lineWidth = 0;
|
|
@@ -9078,11 +9137,11 @@ class TextRenderer {
|
|
|
9078
9137
|
switch (paintOrderLayer) {
|
|
9079
9138
|
case 0 /* PAINT_ORDER_LAYER.FILL */: {
|
|
9080
9139
|
this.ctx.fillStyle = asString(styles.color);
|
|
9081
|
-
if (styles.letterSpacing === 0) {
|
|
9140
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9082
9141
|
this.ctx.fillText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
|
|
9083
9142
|
}
|
|
9084
9143
|
else {
|
|
9085
|
-
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9144
|
+
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9086
9145
|
}
|
|
9087
9146
|
const textShadows = styles.textShadow;
|
|
9088
9147
|
if (textShadows.length && truncatedText.trim().length) {
|
|
@@ -9094,11 +9153,11 @@ class TextRenderer {
|
|
|
9094
9153
|
this.ctx.shadowOffsetX = textShadow.offsetX.number * this.options.scale;
|
|
9095
9154
|
this.ctx.shadowOffsetY = textShadow.offsetY.number * this.options.scale;
|
|
9096
9155
|
this.ctx.shadowBlur = textShadow.blur.number;
|
|
9097
|
-
if (styles.letterSpacing === 0) {
|
|
9156
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9098
9157
|
this.ctx.fillText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
|
|
9099
9158
|
}
|
|
9100
9159
|
else {
|
|
9101
|
-
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9160
|
+
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9102
9161
|
}
|
|
9103
9162
|
});
|
|
9104
9163
|
this.ctx.shadowColor = '';
|
|
@@ -9114,11 +9173,11 @@ class TextRenderer {
|
|
|
9114
9173
|
this.ctx.lineWidth = styles.webkitTextStrokeWidth;
|
|
9115
9174
|
this.ctx.lineJoin =
|
|
9116
9175
|
typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
|
|
9117
|
-
if (styles.letterSpacing === 0) {
|
|
9176
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9118
9177
|
this.ctx.strokeText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
|
|
9119
9178
|
}
|
|
9120
9179
|
else {
|
|
9121
|
-
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9180
|
+
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9122
9181
|
}
|
|
9123
9182
|
this.ctx.strokeStyle = '';
|
|
9124
9183
|
this.ctx.lineWidth = 0;
|
|
@@ -9135,7 +9194,7 @@ class TextRenderer {
|
|
|
9135
9194
|
switch (paintOrderLayer) {
|
|
9136
9195
|
case 0 /* PAINT_ORDER_LAYER.FILL */: {
|
|
9137
9196
|
this.ctx.fillStyle = asString(styles.color);
|
|
9138
|
-
this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number);
|
|
9197
|
+
this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
|
|
9139
9198
|
const textShadows = styles.textShadow;
|
|
9140
9199
|
if (textShadows.length && text.text.trim().length) {
|
|
9141
9200
|
textShadows
|
|
@@ -9146,7 +9205,7 @@ class TextRenderer {
|
|
|
9146
9205
|
this.ctx.shadowOffsetX = textShadow.offsetX.number * this.options.scale;
|
|
9147
9206
|
this.ctx.shadowOffsetY = textShadow.offsetY.number * this.options.scale;
|
|
9148
9207
|
this.ctx.shadowBlur = textShadow.blur.number;
|
|
9149
|
-
this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number);
|
|
9208
|
+
this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
|
|
9150
9209
|
});
|
|
9151
9210
|
this.ctx.shadowColor = '';
|
|
9152
9211
|
this.ctx.shadowOffsetX = 0;
|
|
@@ -9165,11 +9224,11 @@ class TextRenderer {
|
|
|
9165
9224
|
this.ctx.lineJoin =
|
|
9166
9225
|
typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
|
|
9167
9226
|
const baseline = styles.fontSize.number;
|
|
9168
|
-
if (styles.letterSpacing === 0) {
|
|
9227
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9169
9228
|
this.ctx.strokeText(text.text, text.bounds.left, text.bounds.top + baseline);
|
|
9170
9229
|
}
|
|
9171
9230
|
else {
|
|
9172
|
-
this.iterateLettersWithLetterSpacing(text, styles.letterSpacing, baseline, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9231
|
+
this.iterateLettersWithLetterSpacing(text, styles.letterSpacing, baseline, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9173
9232
|
}
|
|
9174
9233
|
this.ctx.strokeStyle = '';
|
|
9175
9234
|
this.ctx.lineWidth = 0;
|
|
@@ -9464,7 +9523,7 @@ class CanvasRenderer extends Renderer {
|
|
|
9464
9523
|
new Vector(bounds.left, bounds.top + bounds.height)
|
|
9465
9524
|
]);
|
|
9466
9525
|
this.ctx.clip();
|
|
9467
|
-
this.textRenderer.renderTextWithLetterSpacing(new TextBounds(container.value, textBounds), styles.letterSpacing, baseline);
|
|
9526
|
+
this.textRenderer.renderTextWithLetterSpacing(new TextBounds(container.value, textBounds), styles.letterSpacing, baseline, styles.writingMode);
|
|
9468
9527
|
this.ctx.restore();
|
|
9469
9528
|
this.ctx.textBaseline = 'alphabetic';
|
|
9470
9529
|
this.ctx.textAlign = 'left';
|
|
@@ -9491,7 +9550,7 @@ class CanvasRenderer extends Renderer {
|
|
|
9491
9550
|
this.ctx.textBaseline = 'middle';
|
|
9492
9551
|
this.ctx.textAlign = 'right';
|
|
9493
9552
|
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);
|
|
9494
|
-
this.textRenderer.renderTextWithLetterSpacing(new TextBounds(paint.listValue, bounds), styles.letterSpacing, computeLineHeight(styles.lineHeight, styles.fontSize.number) / 2 + 2);
|
|
9553
|
+
this.textRenderer.renderTextWithLetterSpacing(new TextBounds(paint.listValue, bounds), styles.letterSpacing, computeLineHeight(styles.lineHeight, styles.fontSize.number) / 2 + 2, styles.writingMode);
|
|
9495
9554
|
this.ctx.textBaseline = 'bottom';
|
|
9496
9555
|
this.ctx.textAlign = 'left';
|
|
9497
9556
|
}
|