Skip to content

Commit

Permalink
Implement RefTestRenderer
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasvh committed Aug 6, 2017
1 parent a289569 commit 93f08c7
Show file tree
Hide file tree
Showing 13 changed files with 409 additions and 84 deletions.
4 changes: 1 addition & 3 deletions src/Bounds.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
import type {Border, BorderSide} from './parsing/border';
import type {BorderRadius} from './parsing/borderRadius';
import type {Padding} from './parsing/padding';
import type Circle from './drawing/Circle';
import type {Path} from './drawing/Path';

import Vector from './drawing/Vector';
import BezierCurve from './drawing/BezierCurve';

export type Path = Array<Vector | BezierCurve> | Circle;

const TOP = 0;
const RIGHT = 1;
const BOTTOM = 2;
Expand Down
6 changes: 3 additions & 3 deletions src/NodeContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import type {Transform} from './parsing/transform';
import type {Visibility} from './parsing/visibility';
import type {zIndex} from './parsing/zIndex';

import type {Bounds, BoundCurves, Path} from './Bounds';
import type {Bounds, BoundCurves} from './Bounds';
import type ImageLoader from './ImageLoader';

import type {Path} from './drawing/Path';
import type TextContainer from './TextContainer';

import Color from './Color';
Expand Down Expand Up @@ -64,7 +64,7 @@ type StyleDeclaration = {
overflow: Overflow,
padding: Padding,
position: Position,
textDecoration: TextDecoration,
textDecoration: TextDecoration | null,
textShadow: Array<TextShadow> | null,
textTransform: TextTransform,
transform: Transform,
Expand Down
47 changes: 35 additions & 12 deletions src/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
'use strict';

import type Color from './Color';
import type {Path} from './drawing/Path';
import type Size from './drawing/Size';
import type Logger from './Logger';

Expand All @@ -12,7 +13,7 @@ import type {TextDecoration} from './parsing/textDecoration';
import type {TextShadow} from './parsing/textShadow';
import type {Matrix} from './parsing/transform';

import type {Path, BoundCurves} from './Bounds';
import type {BoundCurves} from './Bounds';
import type {Gradient} from './Gradient';
import type {ImageStore, ImageElement} from './ImageLoader';
import type NodeContainer from './NodeContainer';
Expand Down Expand Up @@ -49,7 +50,7 @@ export type RenderOptions = {
height: number
};

export interface RenderTarget {
export interface RenderTarget<Output> {
clip(clipPaths: Array<Path>, callback: () => void): void,

drawImage(image: ImageElement, source: Bounds, destination: Bounds): void,
Expand All @@ -58,10 +59,12 @@ export interface RenderTarget {

fill(color: Color): void,

getTarget(): Promise<HTMLCanvasElement>,
getTarget(): Promise<Output>,

rectangle(x: number, y: number, width: number, height: number, color: Color): void,

render(options: RenderOptions): void,

renderLinearGradient(bounds: Bounds, gradient: Gradient): void,

renderRepeat(
Expand All @@ -76,7 +79,7 @@ export interface RenderTarget {
textBounds: Array<TextBounds>,
color: Color,
font: Font,
textDecoration: TextDecoration,
textDecoration: TextDecoration | null,
textShadows: Array<TextShadow> | null
): void,

Expand All @@ -86,12 +89,14 @@ export interface RenderTarget {
}

export default class Renderer {
target: RenderTarget;
target: RenderTarget<*>;
options: RenderOptions;
_opacity: ?number;

constructor(target: RenderTarget, options: RenderOptions) {
constructor(target: RenderTarget<*>, options: RenderOptions) {
this.target = target;
this.options = options;
target.render(options);
}

renderNode(container: NodeContainer) {
Expand All @@ -102,7 +107,7 @@ export default class Renderer {
}

renderNodeContent(container: NodeContainer) {
this.target.clip(container.getClipPaths(), () => {
const callback = () => {
if (container.childNodes.length) {
container.childNodes.forEach(child => {
if (child instanceof TextContainer) {
Expand Down Expand Up @@ -136,11 +141,17 @@ export default class Renderer {
});
}
}
});
};
const paths = container.getClipPaths();
if (paths.length) {
this.target.clip(paths, callback);
} else {
callback();
}
}

renderNodeBackgroundAndBorders(container: NodeContainer) {
this.target.clip(container.parent ? container.parent.getClipPaths() : [], () => {
const callback = () => {
const backgroundPaintingArea = calculateBackgroungPaintingArea(
container.curvedBounds,
container.style.background.backgroundClip
Expand All @@ -156,7 +167,14 @@ export default class Renderer {
container.style.border.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();
}
}

renderBackgroundImage(container: NodeContainer) {
Expand Down Expand Up @@ -213,7 +231,12 @@ export default class Renderer {

renderStack(stack: StackingContext) {
if (stack.container.isVisible()) {
this.target.setOpacity(stack.getOpacity());
const opacity = stack.getOpacity();
if (opacity !== this._opacity) {
this.target.setOpacity(stack.getOpacity());
this._opacity = opacity;
}

const transform = stack.container.style.transform;
if (transform !== null) {
this.target.transform(
Expand Down Expand Up @@ -270,7 +293,7 @@ export default class Renderer {
positiveZIndex.sort(sortByZIndex).forEach(this.renderStack, this);
}

render(stack: StackingContext): Promise<HTMLCanvasElement> {
render(stack: StackingContext): Promise<*> {
if (this.options.backgroundColor) {
this.target.rectangle(
0,
Expand Down
6 changes: 5 additions & 1 deletion src/drawing/BezierCurve.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
/* @flow */
'use strict';
import type {Drawable} from './Path';
import {PATH} from './Path';
import Vector from './Vector';

const lerp = (a: Vector, b: Vector, t: number): Vector => {
return new Vector(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);
};

export default class BezierCurve {
export default class BezierCurve implements Drawable<1> {
type: 1;
start: Vector;
startControl: Vector;
endControl: Vector;
end: Vector;

constructor(start: Vector, startControl: Vector, endControl: Vector, end: Vector) {
this.type = PATH.BEZIER_CURVE;
this.start = start;
this.startControl = startControl;
this.endControl = endControl;
Expand Down
6 changes: 5 additions & 1 deletion src/drawing/Circle.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
/* @flow */
'use strict';
import type {Drawable} from './Path';
import {PATH} from './Path';

export default class Circle {
export default class Circle implements Drawable<2> {
type: 2;
x: number;
y: number;
radius: number;

constructor(x: number, y: number, radius: number) {
this.type = PATH.CIRCLE;
this.x = x;
this.y = y;
this.radius = radius;
Expand Down
20 changes: 20 additions & 0 deletions src/drawing/Path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* @flow */
'use strict';

import type Vector from './Vector';
import type BezierCurve from './BezierCurve';
import type Circle from './Circle';

export const PATH = {
VECTOR: 0,
BEZIER_CURVE: 1,
CIRCLE: 2
};

export type PathType = $Values<typeof PATH>;

export interface Drawable<A> {
type: A
}

export type Path = Array<Vector | BezierCurve> | Circle;
6 changes: 5 additions & 1 deletion src/drawing/Vector.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/* @flow */
'use strict';
import type {Drawable} from './Path';
import {PATH} from './Path';

export default class Vector {
export default class Vector implements Drawable<0> {
type: 0;
x: number;
y: number;

constructor(x: number, y: number) {
this.type = PATH.VECTOR;
this.x = x;
this.y = y;
if (__DEV__) {
Expand Down
33 changes: 18 additions & 15 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* @flow */
'use strict';

import type {RenderTarget} from './Renderer';

import {NodeParser} from './NodeParser';
import Renderer from './Renderer';
import CanvasRenderer from './renderer/CanvasRenderer';
Expand All @@ -19,12 +21,13 @@ export type Options = {
proxy: ?string,
removeContainer: ?boolean,
scale: number,
target: RenderTarget<*> | Array<RenderTarget<*>>,
type: ?string,
windowWidth: number,
windowHeight: number
};

const html2canvas = (element: HTMLElement, config: Options): Promise<HTMLCanvasElement> => {
const html2canvas = (element: HTMLElement, config: Options): Promise<*> => {
if (typeof console === 'object' && typeof console.log === 'function') {
console.log(`html2canvas ${__VERSION__}`);
}
Expand All @@ -37,11 +40,11 @@ const html2canvas = (element: HTMLElement, config: Options): Promise<HTMLCanvasE
const defaultOptions = {
async: true,
allowTaint: false,
canvas: ownerDocument.createElement('canvas'),
imageTimeout: 10000,
proxy: null,
removeContainer: true,
scale: defaultView.devicePixelRatio || 1,
target: new CanvasRenderer(config.canvas),
type: null,
windowWidth: defaultView.innerWidth,
windowHeight: defaultView.innerHeight
Expand All @@ -56,12 +59,6 @@ const html2canvas = (element: HTMLElement, config: Options): Promise<HTMLCanvasE
options.windowHeight
);

const canvas = options.canvas;

if (!(canvas instanceof HTMLCanvasElement)) {
return Promise.reject(__DEV__ ? `Invalid canvas element provided in options` : '');
}

const result = cloneWindow(
ownerDocument,
ownerDocument,
Expand All @@ -83,10 +80,6 @@ const html2canvas = (element: HTMLElement, config: Options): Promise<HTMLCanvasE
const size = options.type === 'view' ? windowBounds : parseDocumentSize(clonedDocument);
const width = size.width;
const height = size.height;
canvas.width = Math.floor(width * options.scale);
canvas.height = Math.floor(height * options.scale);
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;

// http://www.w3.org/TR/css3-background/#special-backgrounds
const backgroundColor =
Expand Down Expand Up @@ -121,10 +114,18 @@ const html2canvas = (element: HTMLElement, config: Options): Promise<HTMLCanvasE
width,
height
};
const canvasTarget = new CanvasRenderer(canvas, renderOptions);

const renderer = new Renderer(canvasTarget, renderOptions);
return renderer.render(stack);
if (Array.isArray(options.target)) {
return Promise.all(
options.target.map(target => {
const renderer = new Renderer(target, renderOptions);
return renderer.render(stack);
})
);
} else {
const renderer = new Renderer(options.target, renderOptions);
return renderer.render(stack);
}
});
});

Expand All @@ -137,4 +138,6 @@ const html2canvas = (element: HTMLElement, config: Options): Promise<HTMLCanvasE
return result;
};

html2canvas.CanvasRenderer = CanvasRenderer;

module.exports = html2canvas;
4 changes: 2 additions & 2 deletions src/parsing/background.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* @flow */
'use strict';

import type {Bounds, BoundCurves, Path} from '../Bounds';
import type {Path} from '../drawing/Path';
import type {Bounds, BoundCurves} from '../Bounds';
import type ImageLoader, {ImageElement} from '../ImageLoader';

import Color from '../Color';
Expand Down
4 changes: 2 additions & 2 deletions src/parsing/textDecoration.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type TextDecoration = {
textDecorationLine: Array<TextDecorationLine>,
textDecorationStyle: TextDecorationStyle,
textDecorationColor: Color | null
} | null;
};

const parseLine = (line: string): TextDecorationLine => {
switch (line) {
Expand Down Expand Up @@ -65,7 +65,7 @@ const parseTextDecorationStyle = (style: string): TextDecorationStyle => {
return TEXT_DECORATION_STYLE.SOLID;
};

export const parseTextDecoration = (style: CSSStyleDeclaration): TextDecoration => {
export const parseTextDecoration = (style: CSSStyleDeclaration): TextDecoration | null => {
const textDecorationLine = parseTextDecorationLine(
style.textDecorationLine ? style.textDecorationLine : style.textDecoration
);
Expand Down
Loading

0 comments on commit 93f08c7

Please sign in to comment.