mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Beging implementing reftests
This commit is contained in:
@ -247,3 +247,5 @@ const NAMED_COLORS = {
|
||||
yellow: [255, 255, 0, null],
|
||||
yellowgreen: [154, 205, 50, null]
|
||||
};
|
||||
|
||||
export const TRANSPARENT = new Color([0, 0, 0, 0]);
|
||||
|
@ -151,34 +151,48 @@ export default class Renderer {
|
||||
}
|
||||
|
||||
renderNodeBackgroundAndBorders(container: NodeContainer) {
|
||||
const HAS_BACKGROUND =
|
||||
!container.style.background.backgroundColor.isTransparent() ||
|
||||
container.style.background.backgroundImage.length;
|
||||
|
||||
const renderableBorders = container.style.border.filter(
|
||||
border =>
|
||||
border.borderStyle !== BORDER_STYLE.NONE && !border.borderColor.isTransparent()
|
||||
);
|
||||
|
||||
const callback = () => {
|
||||
const backgroundPaintingArea = calculateBackgroungPaintingArea(
|
||||
container.curvedBounds,
|
||||
container.style.background.backgroundClip
|
||||
);
|
||||
this.target.clip([backgroundPaintingArea], () => {
|
||||
if (!container.style.background.backgroundColor.isTransparent()) {
|
||||
this.target.fill(container.style.background.backgroundColor);
|
||||
}
|
||||
|
||||
this.renderBackgroundImage(container);
|
||||
});
|
||||
if (HAS_BACKGROUND) {
|
||||
this.target.clip([backgroundPaintingArea], () => {
|
||||
if (!container.style.background.backgroundColor.isTransparent()) {
|
||||
this.target.fill(container.style.background.backgroundColor);
|
||||
}
|
||||
|
||||
container.style.border.forEach((border, side) => {
|
||||
this.renderBackgroundImage(container);
|
||||
});
|
||||
}
|
||||
|
||||
renderableBorders.forEach((border, side) => {
|
||||
this.renderBorder(border, side, container.curvedBounds);
|
||||
});
|
||||
};
|
||||
|
||||
const paths = container.parent ? container.parent.getClipPaths() : [];
|
||||
if (paths.length) {
|
||||
this.target.clip(paths, callback);
|
||||
} else {
|
||||
callback();
|
||||
if (HAS_BACKGROUND || renderableBorders.length) {
|
||||
const paths = container.parent ? container.parent.getClipPaths() : [];
|
||||
if (paths.length) {
|
||||
this.target.clip(paths, callback);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderBackgroundImage(container: NodeContainer) {
|
||||
container.style.background.backgroundImage.reverse().forEach(backgroundImage => {
|
||||
container.style.background.backgroundImage.slice(0).reverse().forEach(backgroundImage => {
|
||||
if (backgroundImage.source.method === 'url' && backgroundImage.source.args.length) {
|
||||
this.renderBackgroundRepeat(container, backgroundImage);
|
||||
} else {
|
||||
@ -224,9 +238,7 @@ export default class Renderer {
|
||||
}
|
||||
|
||||
renderBorder(border: Border, side: BorderSide, curvePoints: BoundCurves) {
|
||||
if (border.borderStyle !== BORDER_STYLE.NONE && !border.borderColor.isTransparent()) {
|
||||
this.target.drawShape(parsePathForBorder(curvePoints, side), border.borderColor);
|
||||
}
|
||||
this.target.drawShape(parsePathForBorder(curvePoints, side), border.borderColor);
|
||||
}
|
||||
|
||||
renderStack(stack: StackingContext) {
|
||||
|
18
src/index.js
18
src/index.js
@ -10,7 +10,7 @@ import Logger from './Logger';
|
||||
import ImageLoader from './ImageLoader';
|
||||
import {Bounds, parseDocumentSize} from './Bounds';
|
||||
import {cloneWindow} from './Clone';
|
||||
import Color from './Color';
|
||||
import Color, {TRANSPARENT} from './Color';
|
||||
import {FontMetrics} from './Font';
|
||||
|
||||
export type Options = {
|
||||
@ -24,7 +24,9 @@ export type Options = {
|
||||
target: RenderTarget<*> | Array<RenderTarget<*>>,
|
||||
type: ?string,
|
||||
windowWidth: number,
|
||||
windowHeight: number
|
||||
windowHeight: number,
|
||||
offsetX: number,
|
||||
offsetY: number
|
||||
};
|
||||
|
||||
const html2canvas = (element: HTMLElement, config: Options): Promise<*> => {
|
||||
@ -47,14 +49,16 @@ const html2canvas = (element: HTMLElement, config: Options): Promise<*> => {
|
||||
target: new CanvasRenderer(config.canvas),
|
||||
type: null,
|
||||
windowWidth: defaultView.innerWidth,
|
||||
windowHeight: defaultView.innerHeight
|
||||
windowHeight: defaultView.innerHeight,
|
||||
offsetX: defaultView.pageXOffset,
|
||||
offsetY: defaultView.pageYOffset
|
||||
};
|
||||
|
||||
const options = {...defaultOptions, ...config};
|
||||
|
||||
const windowBounds = new Bounds(
|
||||
defaultView.pageXOffset,
|
||||
defaultView.pageYOffset,
|
||||
options.offsetX,
|
||||
options.offsetY,
|
||||
options.windowWidth,
|
||||
options.windowHeight
|
||||
);
|
||||
@ -91,6 +95,10 @@ const html2canvas = (element: HTMLElement, config: Options): Promise<*> => {
|
||||
: stack.container.style.background.backgroundColor
|
||||
: null;
|
||||
|
||||
if (backgroundColor === stack.container.style.background.backgroundColor) {
|
||||
stack.container.style.background.backgroundColor = TRANSPARENT;
|
||||
}
|
||||
|
||||
return imageLoader.ready().then(imageStore => {
|
||||
if (options.removeContainer === true) {
|
||||
if (container.parentNode) {
|
||||
|
@ -350,11 +350,13 @@ const parseBackgroundImage = (image: string, imageLoader: ImageLoader): Array<Ba
|
||||
const key = imageLoader.loadImage(args[0]);
|
||||
args = key ? [key] : [];
|
||||
}
|
||||
results.push({
|
||||
prefix,
|
||||
method,
|
||||
args
|
||||
});
|
||||
if (method !== 'none') {
|
||||
results.push({
|
||||
prefix,
|
||||
method,
|
||||
args
|
||||
});
|
||||
}
|
||||
}
|
||||
args = [];
|
||||
method = definition = '';
|
||||
|
@ -39,7 +39,7 @@ export const parseBorder = (style: CSSStyleDeclaration): Array<Border> => {
|
||||
return SIDES.map(side => {
|
||||
const borderColor = new Color(style.getPropertyValue(`border-${side}-color`));
|
||||
const borderStyle = parseBorderStyle(style.getPropertyValue(`border-${side}-style`));
|
||||
const borderWidth = parseInt(style.getPropertyValue(`border-${side}-width`), 10);
|
||||
const borderWidth = parseFloat(style.getPropertyValue(`border-${side}-width`));
|
||||
return {
|
||||
borderColor,
|
||||
borderStyle,
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
import {parse} from 'url';
|
||||
|
||||
import type {RenderTarget, RenderOptions} from '../Renderer';
|
||||
import type Color from '../Color';
|
||||
@ -33,10 +34,11 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
this.indent = 0;
|
||||
this.lines = [];
|
||||
options.logger.log(`RefTest renderer initialized`);
|
||||
this.writeLine(`Window: [${options.width}, ${options.height}]`);
|
||||
}
|
||||
|
||||
clip(clipPaths: Array<Path>, callback: () => void) {
|
||||
this.writeLine(`Clip ${clipPaths.map(this.formatPath, this).join(', ')}`);
|
||||
this.writeLine(`Clip: ${clipPaths.map(this.formatPath, this).join(' | ')}`);
|
||||
this.indent += 2;
|
||||
callback();
|
||||
this.indent -= 2;
|
||||
@ -44,18 +46,18 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
|
||||
drawImage(image: ImageElement, source: Bounds, destination: Bounds) {
|
||||
this.writeLine(
|
||||
`Draw image ${this.formatImage(image)} (source: ${this.formatBounds(
|
||||
`Draw image: ${this.formatImage(image)} (source: ${this.formatBounds(
|
||||
source
|
||||
)} (destination: ${this.formatBounds(source)})`
|
||||
)}) (destination: ${this.formatBounds(source)})`
|
||||
);
|
||||
}
|
||||
|
||||
drawShape(path: Path, color: Color) {
|
||||
this.writeLine(`Shape ${color.toString()} ${this.formatPath(path)}`);
|
||||
this.writeLine(`Shape: ${color.toString()} ${this.formatPath(path)}`);
|
||||
}
|
||||
|
||||
fill(color: Color) {
|
||||
this.writeLine(`Fill ${color.toString()}`);
|
||||
this.writeLine(`Fill: ${color.toString()}`);
|
||||
}
|
||||
|
||||
getTarget(): Promise<string> {
|
||||
@ -64,7 +66,7 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
|
||||
rectangle(x: number, y: number, width: number, height: number, color: Color) {
|
||||
const list = [x, y, width, height].map(v => Math.round(v)).join(', ');
|
||||
this.writeLine(`Rectangle [${list}] ${color.toString()}`);
|
||||
this.writeLine(`Rectangle: [${list}] ${color.toString()}`);
|
||||
}
|
||||
|
||||
formatBounds(bounds: Bounds): string {
|
||||
@ -73,8 +75,10 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
}
|
||||
|
||||
formatImage(image: ImageElement): string {
|
||||
// $FlowFixMe
|
||||
return image.tagName === 'CANVAS' ? 'Canvas' : `Image src="${image.src}"`;
|
||||
return image.tagName === 'CANVAS'
|
||||
? 'Canvas'
|
||||
: // $FlowFixMe
|
||||
`Image ("${parse(image.src).pathname.substring(0, 100)}")`;
|
||||
}
|
||||
|
||||
formatPath(path: Path): string {
|
||||
@ -86,7 +90,7 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
const string = path
|
||||
.map(v => {
|
||||
if (v.type === PATH.VECTOR) {
|
||||
return `Vector(x: ${Math.round(v.x)}, y: ${Math.round(v.y)}))`;
|
||||
return `Vector(x: ${Math.round(v.x)}, y: ${Math.round(v.y)})`;
|
||||
}
|
||||
if (v.type === PATH.BEZIER_CURVE) {
|
||||
const values = [
|
||||
@ -102,7 +106,7 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
return `BezierCurve(${values.join(', ')})`;
|
||||
}
|
||||
})
|
||||
.join(', ');
|
||||
.join(' > ');
|
||||
return `Path (${string})`;
|
||||
}
|
||||
|
||||
@ -114,12 +118,14 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
`y1: ${Math.round(gradient.direction.y1)}`
|
||||
];
|
||||
|
||||
const stops = gradient.colorStops.map(stop => `${stop.color.toString()} ${stop.stop}px`);
|
||||
const stops = gradient.colorStops.map(
|
||||
stop => `${stop.color.toString()} ${Math.round(stop.stop * 100) / 100}`
|
||||
);
|
||||
|
||||
this.writeLine(
|
||||
`${this.formatBounds(bounds)} linear-gradient(${direction.join(', ')} ${stops.join(
|
||||
`Gradient: ${this.formatBounds(bounds)} linear-gradient(${direction.join(
|
||||
', '
|
||||
)})`
|
||||
)} ${stops.join(', ')})`
|
||||
);
|
||||
}
|
||||
|
||||
@ -131,7 +137,7 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
offsetY: number
|
||||
) {
|
||||
this.writeLine(
|
||||
`Repeat ${this.formatImage(
|
||||
`Repeat: ${this.formatImage(
|
||||
image
|
||||
)} [${offsetX}, ${offsetY}] Size (${imageSize.width}, ${imageSize.height}) ${this.formatPath(
|
||||
path
|
||||
@ -151,7 +157,7 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
font.fontVariant,
|
||||
font.fontWeight,
|
||||
font.fontSize,
|
||||
font.fontFamily
|
||||
font.fontFamily.replace(/"/g, '')
|
||||
]
|
||||
.join(' ')
|
||||
.split(',')[0];
|
||||
@ -167,7 +173,7 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
: '';
|
||||
|
||||
this.writeLine(
|
||||
`Text ${color.toString()} ${fontString}${shadowString}${textDecorationString}`
|
||||
`Text: ${color.toString()} ${fontString}${shadowString}${textDecorationString}`
|
||||
);
|
||||
|
||||
this.indent += 2;
|
||||
@ -231,18 +237,22 @@ class RefTestRenderer implements RenderTarget<string> {
|
||||
}
|
||||
|
||||
setOpacity(opacity: number) {
|
||||
this.writeLine(`Opacity ${opacity}`);
|
||||
this.writeLine(`Opacity: ${opacity}`);
|
||||
}
|
||||
|
||||
transform(offsetX: number, offsetY: number, matrix: Matrix, callback: () => void) {
|
||||
this.writeLine(`Transform (${offsetX}, ${offsetY}) [${matrix.join(', ')}]`);
|
||||
this.writeLine(
|
||||
`Transform: (${Math.round(offsetX)}, ${Math.round(offsetY)}) [${matrix
|
||||
.map(v => Math.round(v * 100) / 100)
|
||||
.join(', ')}]`
|
||||
);
|
||||
this.indent += 2;
|
||||
callback();
|
||||
this.indent -= 2;
|
||||
}
|
||||
|
||||
writeLine(text: string) {
|
||||
this.lines.push(`${new Array(this.indent).join(' ')}${text}`);
|
||||
this.lines.push(`${new Array(this.indent + 1).join(' ')}${text}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user