Skip to content
Open
4 changes: 2 additions & 2 deletions src/dom/node-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ const LIST_OWNERS = ['OL', 'UL', 'MENU'];
const parseNodeTree = (context: Context, node: Node, parent: ElementContainer, root: ElementContainer) => {
for (let childNode = node.firstChild, nextNode; childNode; childNode = nextNode) {
nextNode = childNode.nextSibling;

if (isTextNode(childNode) && childNode.data.trim().length > 0) {
// Fixes #2238 #1624 - Fix the issue of TextNode content being overlooked in rendering due to being perceived as blank by trim().
if (isTextNode(childNode) && childNode.data.length > 0) {
parent.textNodes.push(new TextContainer(context, childNode, parent.styles));
} else if (isElementNode(childNode)) {
if (isSlotElement(childNode) && childNode.assignedNodes) {
Expand Down
39 changes: 14 additions & 25 deletions src/render/canvas/canvas-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,14 @@ export class CanvasRenderer extends Renderer {

renderTextWithLetterSpacing(text: TextBounds, letterSpacing: number, baseline: number): void {
if (letterSpacing === 0) {
this.ctx.fillText(text.text, text.bounds.left, text.bounds.top + baseline);
// Fixed an issue with characters moving up in non-Firefox.
// https://github.com/niklasvh/html2canvas/issues/2107#issuecomment-692462900
if (navigator.userAgent.indexOf('Firefox') === -1){
this.ctx.textBaseline = 'ideographic';
this.ctx.fillText(text.text, text.bounds.left, text.bounds.top + text.bounds.height);
} else {
this.ctx.fillText(text.text, text.bounds.left, text.bounds.top + baseline);
}
} else {
const letters = segmentGraphemes(text.text);
letters.reduce((left, letter) => {
Expand Down Expand Up @@ -181,7 +188,7 @@ export class CanvasRenderer extends Renderer {
this.ctx.direction = styles.direction === DIRECTION.RTL ? 'rtl' : 'ltr';
this.ctx.textAlign = 'left';
this.ctx.textBaseline = 'alphabetic';
const {baseline, middle} = this.fontMetrics.getMetrics(fontFamily, fontSize);
const {baseline} = this.fontMetrics.getMetrics(fontFamily, fontSize);
const paintOrder = styles.paintOrder;

text.textBounds.forEach((text) => {
Expand Down Expand Up @@ -214,35 +221,17 @@ export class CanvasRenderer extends Renderer {
if (styles.textDecorationLine.length) {
this.ctx.fillStyle = asString(styles.textDecorationColor || styles.color);
styles.textDecorationLine.forEach((textDecorationLine) => {
// Fix the issue where textDecorationLine exhibits x-axis positioning errors on high-resolution devices due to varying devicePixelRatio, corrected by using relative values of element heights.
var decorationLineHeight = 1;
switch (textDecorationLine) {
case TEXT_DECORATION_LINE.UNDERLINE:
// Draws a line at the baseline of the font
// TODO As some browsers display the line as more than 1px if the font-size is big,
// need to take that into account both in position and size
this.ctx.fillRect(
text.bounds.left,
Math.round(text.bounds.top + baseline),
text.bounds.width,
1
);

this.ctx.fillRect(text.bounds.left, text.bounds.top + text.bounds.height - decorationLineHeight, text.bounds.width, decorationLineHeight);
break;
case TEXT_DECORATION_LINE.OVERLINE:
this.ctx.fillRect(
text.bounds.left,
Math.round(text.bounds.top),
text.bounds.width,
1
);
this.ctx.fillRect(text.bounds.left, text.bounds.top , text.bounds.width, decorationLineHeight);
break;
case TEXT_DECORATION_LINE.LINE_THROUGH:
// TODO try and find exact position for line-through
this.ctx.fillRect(
text.bounds.left,
Math.ceil(text.bounds.top + middle),
text.bounds.width,
1
);
this.ctx.fillRect(text.bounds.left, text.bounds.top + (text.bounds.height / 2 - decorationLineHeight / 2), text.bounds.width, decorationLineHeight);
break;
}
});
Expand Down