mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
fix: test for ios range line break error (#2635)
This commit is contained in:
parent
7a06d0c2c2
commit
f43f942fcd
@ -1,3 +1,5 @@
|
||||
import {fromCodePoint, toCodePoints} from 'css-line-break';
|
||||
|
||||
const testRangeBounds = (document: Document) => {
|
||||
const TEST_HEIGHT = 123;
|
||||
|
||||
@ -22,6 +24,45 @@ const testRangeBounds = (document: Document) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
const testIOSLineBreak = (document: Document) => {
|
||||
const testElement = document.createElement('boundtest');
|
||||
testElement.style.width = '50px';
|
||||
testElement.style.display = 'block';
|
||||
testElement.style.fontSize = '12px';
|
||||
testElement.style.letterSpacing = '0px';
|
||||
testElement.style.wordSpacing = '0px';
|
||||
document.body.appendChild(testElement);
|
||||
const range = document.createRange();
|
||||
|
||||
testElement.innerHTML = typeof ''.repeat === 'function' ? '👨'.repeat(10) : '';
|
||||
|
||||
const node = testElement.firstChild as Text;
|
||||
|
||||
const textList = toCodePoints(node.data).map((i) => fromCodePoint(i));
|
||||
let offset = 0;
|
||||
let prev: DOMRect = {} as DOMRect;
|
||||
|
||||
// ios 13 does not handle range getBoundingClientRect line changes correctly #2177
|
||||
const supports = textList.every((text, i) => {
|
||||
range.setStart(node, offset);
|
||||
range.setEnd(node, offset + text.length);
|
||||
const rect = range.getBoundingClientRect();
|
||||
|
||||
offset += text.length;
|
||||
const boundAhead = rect.x > prev.x || rect.y > prev.y;
|
||||
|
||||
prev = rect;
|
||||
if (i === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return boundAhead;
|
||||
});
|
||||
|
||||
document.body.removeChild(testElement);
|
||||
return supports;
|
||||
};
|
||||
|
||||
const testCORS = (): boolean => typeof new Image().crossOrigin !== 'undefined';
|
||||
|
||||
const testResponseType = (): boolean => typeof new XMLHttpRequest().responseType === 'string';
|
||||
@ -132,6 +173,12 @@ export const FEATURES = {
|
||||
Object.defineProperty(FEATURES, 'SUPPORT_RANGE_BOUNDS', {value});
|
||||
return value;
|
||||
},
|
||||
get SUPPORT_WORD_BREAKING(): boolean {
|
||||
'use strict';
|
||||
const value = FEATURES.SUPPORT_RANGE_BOUNDS && testIOSLineBreak(document);
|
||||
Object.defineProperty(FEATURES, 'SUPPORT_WORD_BREAKING', {value});
|
||||
return value;
|
||||
},
|
||||
get SUPPORT_SVG_DRAWING(): boolean {
|
||||
'use strict';
|
||||
const value = testSVG(document);
|
||||
|
@ -15,6 +15,20 @@ export class Bounds {
|
||||
clientRect.height
|
||||
);
|
||||
}
|
||||
|
||||
static fromDOMRectList(context: Context, domRectList: DOMRectList): Bounds {
|
||||
const domRect = domRectList[0];
|
||||
return domRect
|
||||
? new Bounds(
|
||||
domRect.x + context.windowBounds.left,
|
||||
domRect.y + context.windowBounds.top,
|
||||
domRect.width,
|
||||
domRect.height
|
||||
)
|
||||
: Bounds.EMPTY;
|
||||
}
|
||||
|
||||
static EMPTY = new Bounds(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
export const parseBounds = (context: Context, node: Element): Bounds => {
|
||||
|
@ -27,7 +27,16 @@ export const parseTextBounds = (
|
||||
textList.forEach((text) => {
|
||||
if (styles.textDecorationLine.length || text.trim().length > 0) {
|
||||
if (FEATURES.SUPPORT_RANGE_BOUNDS) {
|
||||
if (!FEATURES.SUPPORT_WORD_BREAKING) {
|
||||
textBounds.push(
|
||||
new TextBounds(
|
||||
text,
|
||||
Bounds.fromDOMRectList(context, createRange(node, offset, text.length).getClientRects())
|
||||
)
|
||||
);
|
||||
} else {
|
||||
textBounds.push(new TextBounds(text, getRangeBounds(context, node, offset, text.length)));
|
||||
}
|
||||
} else {
|
||||
const replacementNode = node.splitText(text.length);
|
||||
textBounds.push(new TextBounds(text, getWrapperBounds(context, node)));
|
||||
@ -58,10 +67,10 @@ const getWrapperBounds = (context: Context, node: Text): Bounds => {
|
||||
}
|
||||
}
|
||||
|
||||
return new Bounds(0, 0, 0, 0);
|
||||
return Bounds.EMPTY;
|
||||
};
|
||||
|
||||
const getRangeBounds = (context: Context, node: Text, offset: number, length: number): Bounds => {
|
||||
const createRange = (node: Text, offset: number, length: number): Range => {
|
||||
const ownerDocument = node.ownerDocument;
|
||||
if (!ownerDocument) {
|
||||
throw new Error('Node has no owner document');
|
||||
@ -69,7 +78,11 @@ const getRangeBounds = (context: Context, node: Text, offset: number, length: nu
|
||||
const range = ownerDocument.createRange();
|
||||
range.setStart(node, offset);
|
||||
range.setEnd(node, offset + length);
|
||||
return Bounds.fromClientRect(context, range.getBoundingClientRect());
|
||||
return range;
|
||||
};
|
||||
|
||||
const getRangeBounds = (context: Context, node: Text, offset: number, length: number): Bounds => {
|
||||
return Bounds.fromClientRect(context, createRange(node, offset, length).getBoundingClientRect());
|
||||
};
|
||||
|
||||
const breakText = (value: string, styles: CSSParsedDeclaration): string[] => {
|
||||
|
Loading…
Reference in New Issue
Block a user