mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Begin implementing overflow clipping
This commit is contained in:
@ -171,6 +171,24 @@ const createPathFromCurves = (
|
||||
return path;
|
||||
};
|
||||
|
||||
export const calculateBorderBoxPath = (curves: BoundCurves): Path => {
|
||||
return [
|
||||
curves.topLeftOuter,
|
||||
curves.topRightOuter,
|
||||
curves.bottomRightOuter,
|
||||
curves.bottomLeftOuter
|
||||
];
|
||||
};
|
||||
|
||||
export const calculatePaddingBoxPath = (curves: BoundCurves): Path => {
|
||||
return [
|
||||
curves.topLeftInner,
|
||||
curves.topRightInner,
|
||||
curves.bottomRightInner,
|
||||
curves.bottomLeftInner
|
||||
];
|
||||
};
|
||||
|
||||
export const parseBoundCurves = (
|
||||
bounds: Bounds,
|
||||
borders: Array<Border>,
|
||||
|
@ -16,7 +16,6 @@ import type {ImageStore} from './ImageLoader';
|
||||
import type StackingContext from './StackingContext';
|
||||
|
||||
import {
|
||||
BACKGROUND_CLIP,
|
||||
BACKGROUND_ORIGIN,
|
||||
calculateBackgroungPaintingArea,
|
||||
calculateBackgroundPosition,
|
||||
@ -25,10 +24,10 @@ import {
|
||||
} from './parsing/background';
|
||||
import {BORDER_STYLE} from './parsing/border';
|
||||
import {
|
||||
parseBoundCurves,
|
||||
parsePathForBorder,
|
||||
calculateContentBox,
|
||||
calculatePaddingBox
|
||||
calculatePaddingBox,
|
||||
calculatePaddingBoxPath
|
||||
} from './Bounds';
|
||||
|
||||
export type RenderOptions = {
|
||||
@ -54,6 +53,15 @@ export default class CanvasRenderer {
|
||||
}
|
||||
|
||||
renderNodeContent(container: NodeContainer) {
|
||||
this.ctx.save();
|
||||
const clipPaths = container.getClipPaths();
|
||||
if (clipPaths.length) {
|
||||
clipPaths.forEach(path => {
|
||||
this.path(path);
|
||||
this.ctx.clip();
|
||||
});
|
||||
}
|
||||
|
||||
if (container.textNodes.length) {
|
||||
this.ctx.fillStyle = container.style.color.toString();
|
||||
this.ctx.font = [
|
||||
@ -92,17 +100,24 @@ export default class CanvasRenderer {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.ctx.restore();
|
||||
}
|
||||
|
||||
renderNodeBackgroundAndBorders(container: NodeContainer) {
|
||||
const curvePoints = parseBoundCurves(
|
||||
container.bounds,
|
||||
container.style.border,
|
||||
container.style.borderRadius
|
||||
);
|
||||
this.ctx.save();
|
||||
if (container.parent) {
|
||||
const clipPaths = container.parent.getClipPaths();
|
||||
if (clipPaths.length) {
|
||||
clipPaths.forEach(path => {
|
||||
this.path(path);
|
||||
this.ctx.clip();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const backgroungPaintingArea = calculateBackgroungPaintingArea(
|
||||
curvePoints,
|
||||
container.curvedBounds,
|
||||
container.style.background.backgroundClip
|
||||
);
|
||||
this.path(backgroungPaintingArea);
|
||||
@ -116,8 +131,9 @@ export default class CanvasRenderer {
|
||||
this.renderBackgroundImage(container);
|
||||
this.ctx.restore();
|
||||
container.style.border.forEach((border, side) => {
|
||||
this.renderBorder(border, side, curvePoints);
|
||||
this.renderBorder(border, side, container.curvedBounds);
|
||||
});
|
||||
this.ctx.restore();
|
||||
}
|
||||
|
||||
renderTextNode(textContainer: TextContainer) {
|
||||
|
@ -7,6 +7,7 @@ import type {BorderRadius} from './parsing/borderRadius';
|
||||
import type {DisplayBit} from './parsing/display';
|
||||
import type {Float} from './parsing/float';
|
||||
import type {Font} from './parsing/font';
|
||||
import type {Overflow} from './parsing/overflow';
|
||||
import type {Padding} from './parsing/padding';
|
||||
import type {Position} from './parsing/position';
|
||||
import type {TextTransform} from './parsing/textTransform';
|
||||
@ -14,7 +15,7 @@ import type {TextDecoration} from './parsing/textDecoration';
|
||||
import type {Transform} from './parsing/transform';
|
||||
import type {zIndex} from './parsing/zIndex';
|
||||
|
||||
import type {Bounds} from './Bounds';
|
||||
import type {Bounds, BoundCurves, Path} from './Bounds';
|
||||
import type ImageLoader from './ImageLoader';
|
||||
|
||||
import type TextContainer from './TextContainer';
|
||||
@ -29,6 +30,7 @@ import {parseDisplay, DISPLAY} from './parsing/display';
|
||||
import {parseCSSFloat, FLOAT} from './parsing/float';
|
||||
import {parseFont} from './parsing/font';
|
||||
import {parseLetterSpacing} from './parsing/letterSpacing';
|
||||
import {parseOverflow, OVERFLOW} from './parsing/overflow';
|
||||
import {parsePadding} from './parsing/padding';
|
||||
import {parsePosition, POSITION} from './parsing/position';
|
||||
import {parseTextDecoration} from './parsing/textDecoration';
|
||||
@ -36,7 +38,7 @@ import {parseTextTransform} from './parsing/textTransform';
|
||||
import {parseTransform} from './parsing/transform';
|
||||
import {parseZIndex} from './parsing/zIndex';
|
||||
|
||||
import {parseBounds} from './Bounds';
|
||||
import {parseBounds, parseBoundCurves, calculatePaddingBoxPath} from './Bounds';
|
||||
|
||||
type StyleDeclaration = {
|
||||
background: Background,
|
||||
@ -48,6 +50,7 @@ type StyleDeclaration = {
|
||||
font: Font,
|
||||
letterSpacing: number,
|
||||
opacity: number,
|
||||
overflow: Overflow,
|
||||
padding: Padding,
|
||||
position: Position,
|
||||
textDecoration: TextDecoration,
|
||||
@ -62,6 +65,7 @@ export default class NodeContainer {
|
||||
style: StyleDeclaration;
|
||||
textNodes: Array<TextContainer>;
|
||||
bounds: Bounds;
|
||||
curvedBounds: BoundCurves;
|
||||
image: ?string;
|
||||
|
||||
constructor(node: HTMLElement, parent: ?NodeContainer, imageLoader: ImageLoader) {
|
||||
@ -80,6 +84,7 @@ export default class NodeContainer {
|
||||
font: parseFont(style),
|
||||
letterSpacing: parseLetterSpacing(style.letterSpacing),
|
||||
opacity: parseFloat(style.opacity),
|
||||
overflow: parseOverflow(style.overflow),
|
||||
padding: parsePadding(style),
|
||||
position: parsePosition(style.position),
|
||||
textDecoration: parseTextDecoration(style),
|
||||
@ -97,12 +102,27 @@ export default class NodeContainer {
|
||||
// $FlowFixMe
|
||||
node.tagName === 'IMG' ? imageLoader.loadImage(node.currentSrc || node.src) : null;
|
||||
this.bounds = parseBounds(node);
|
||||
this.curvedBounds = parseBoundCurves(
|
||||
this.bounds,
|
||||
this.style.border,
|
||||
this.style.borderRadius
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
this.name = `${node.tagName.toLowerCase()}${node.id
|
||||
? `#${node.id}`
|
||||
: ''}${node.className.split(' ').map(s => (s.length ? `.${s}` : '')).join('')}`;
|
||||
}
|
||||
}
|
||||
getClipPaths(): Array<Path> {
|
||||
const parentClips = this.parent ? this.parent.getClipPaths() : [];
|
||||
const isClipped =
|
||||
this.style.overflow === OVERFLOW.HIDDEN || this.style.overflow === OVERFLOW.SCROLL;
|
||||
|
||||
return isClipped
|
||||
? parentClips.concat([calculatePaddingBoxPath(this.curvedBounds)])
|
||||
: parentClips;
|
||||
}
|
||||
isInFlow(): boolean {
|
||||
return this.isRootElement() && !this.isFloating() && !this.isAbsolutelyPositioned();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import Color from '../Color';
|
||||
import Length from '../Length';
|
||||
import Size from '../Size';
|
||||
import Vector from '../Vector';
|
||||
import {calculateBorderBoxPath, calculatePaddingBoxPath} from '../Bounds';
|
||||
|
||||
export type Background = {
|
||||
backgroundImage: Array<BackgroundImage>,
|
||||
@ -123,20 +124,10 @@ export const calculateBackgroungPaintingArea = (
|
||||
// TODO support CONTENT_BOX
|
||||
switch (clip) {
|
||||
case BACKGROUND_CLIP.BORDER_BOX:
|
||||
return [
|
||||
curves.topLeftOuter,
|
||||
curves.topRightOuter,
|
||||
curves.bottomRightOuter,
|
||||
curves.bottomLeftOuter
|
||||
];
|
||||
return calculateBorderBoxPath(curves);
|
||||
case BACKGROUND_CLIP.PADDING_BOX:
|
||||
default:
|
||||
return [
|
||||
curves.topLeftInner,
|
||||
curves.topRightInner,
|
||||
curves.bottomRightInner,
|
||||
curves.bottomLeftInner
|
||||
];
|
||||
return calculatePaddingBoxPath(curves);
|
||||
}
|
||||
};
|
||||
|
||||
|
25
src/parsing/overflow.js
Normal file
25
src/parsing/overflow.js
Normal file
@ -0,0 +1,25 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
export const OVERFLOW = {
|
||||
VISIBLE: 0,
|
||||
HIDDEN: 1,
|
||||
SCROLL: 2,
|
||||
AUTO: 3
|
||||
};
|
||||
|
||||
export type Overflow = $Values<typeof OVERFLOW>;
|
||||
|
||||
export const parseOverflow = (overflow: string): Overflow => {
|
||||
switch (overflow) {
|
||||
case 'hidden':
|
||||
return OVERFLOW.HIDDEN;
|
||||
case 'scroll':
|
||||
return OVERFLOW.SCROLL;
|
||||
case 'auto':
|
||||
return OVERFLOW.AUTO;
|
||||
case 'visible':
|
||||
default:
|
||||
return OVERFLOW.VISIBLE;
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user