UNPKG

html2canvas

Version:
328 lines (286 loc) 16.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _Bounds = require('./Bounds'); var _Font = require('./Font'); var _Gradient = require('./Gradient'); var _TextContainer = require('./TextContainer'); var _TextContainer2 = _interopRequireDefault(_TextContainer); var _background = require('./parsing/background'); var _border = require('./parsing/border'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Renderer = function () { function Renderer(target, options) { _classCallCheck(this, Renderer); this.target = target; this.options = options; target.render(options); } _createClass(Renderer, [{ key: 'renderNode', value: function renderNode(container) { if (container.isVisible()) { this.renderNodeBackgroundAndBorders(container); this.renderNodeContent(container); } } }, { key: 'renderNodeContent', value: function renderNodeContent(container) { var _this = this; var callback = function callback() { if (container.childNodes.length) { container.childNodes.forEach(function (child) { if (child instanceof _TextContainer2.default) { var style = child.parent.style; _this.target.renderTextNode(child.bounds, style.color, style.font, style.textDecoration, style.textShadow); } else { _this.target.drawShape(child, container.style.color); } }); } if (container.image) { var _image = _this.options.imageStore.get(container.image); if (_image) { var contentBox = (0, _Bounds.calculateContentBox)(container.bounds, container.style.padding, container.style.border); var _width = typeof _image.width === 'number' && _image.width > 0 ? _image.width : contentBox.width; var _height = typeof _image.height === 'number' && _image.height > 0 ? _image.height : contentBox.height; if (_width > 0 && _height > 0) { _this.target.clip([(0, _Bounds.calculatePaddingBoxPath)(container.curvedBounds)], function () { _this.target.drawImage(_image, new _Bounds.Bounds(0, 0, _width, _height), contentBox); }); } } } }; var paths = container.getClipPaths(); if (paths.length) { this.target.clip(paths, callback); } else { callback(); } } }, { key: 'renderNodeBackgroundAndBorders', value: function renderNodeBackgroundAndBorders(container) { var _this2 = this; var HAS_BACKGROUND = !container.style.background.backgroundColor.isTransparent() || container.style.background.backgroundImage.length; var hasRenderableBorders = container.style.border.some(function (border) { return border.borderStyle !== _border.BORDER_STYLE.NONE && !border.borderColor.isTransparent(); }); var callback = function callback() { var backgroundPaintingArea = (0, _background.calculateBackgroungPaintingArea)(container.curvedBounds, container.style.background.backgroundClip); if (HAS_BACKGROUND) { _this2.target.clip([backgroundPaintingArea], function () { if (!container.style.background.backgroundColor.isTransparent()) { _this2.target.fill(container.style.background.backgroundColor); } _this2.renderBackgroundImage(container); }); } container.style.border.forEach(function (border, side) { if (border.borderStyle !== _border.BORDER_STYLE.NONE && !border.borderColor.isTransparent()) { _this2.renderBorder(border, side, container.curvedBounds); } }); }; if (HAS_BACKGROUND || hasRenderableBorders) { var paths = container.parent ? container.parent.getClipPaths() : []; if (paths.length) { this.target.clip(paths, callback); } else { callback(); } } } }, { key: 'renderBackgroundImage', value: function renderBackgroundImage(container) { var _this3 = this; container.style.background.backgroundImage.slice(0).reverse().forEach(function (backgroundImage) { if (backgroundImage.source.method === 'url' && backgroundImage.source.args.length) { _this3.renderBackgroundRepeat(container, backgroundImage); } else if (/gradient/i.test(backgroundImage.source.method)) { _this3.renderBackgroundGradient(container, backgroundImage); } }); } }, { key: 'renderBackgroundRepeat', value: function renderBackgroundRepeat(container, background) { var image = this.options.imageStore.get(background.source.args[0]); if (image) { var backgroundPositioningArea = (0, _background.calculateBackgroungPositioningArea)(container.style.background.backgroundOrigin, container.bounds, container.style.padding, container.style.border); var backgroundImageSize = (0, _background.calculateBackgroundSize)(background, image, backgroundPositioningArea); var position = (0, _background.calculateBackgroundPosition)(background.position, backgroundImageSize, backgroundPositioningArea); var _path = (0, _background.calculateBackgroundRepeatPath)(background, position, backgroundImageSize, backgroundPositioningArea, container.bounds); var _offsetX = Math.round(backgroundPositioningArea.left + position.x); var _offsetY = Math.round(backgroundPositioningArea.top + position.y); this.target.renderRepeat(_path, image, backgroundImageSize, _offsetX, _offsetY); } } }, { key: 'renderBackgroundGradient', value: function renderBackgroundGradient(container, background) { var backgroundPositioningArea = (0, _background.calculateBackgroungPositioningArea)(container.style.background.backgroundOrigin, container.bounds, container.style.padding, container.style.border); var backgroundImageSize = (0, _background.calculateGradientBackgroundSize)(background, backgroundPositioningArea); var position = (0, _background.calculateBackgroundPosition)(background.position, backgroundImageSize, backgroundPositioningArea); var gradientBounds = new _Bounds.Bounds(Math.round(backgroundPositioningArea.left + position.x), Math.round(backgroundPositioningArea.top + position.y), backgroundImageSize.width, backgroundImageSize.height); var gradient = (0, _Gradient.parseGradient)(container, background.source, gradientBounds); if (gradient) { switch (gradient.type) { case _Gradient.GRADIENT_TYPE.LINEAR_GRADIENT: // $FlowFixMe this.target.renderLinearGradient(gradientBounds, gradient); break; case _Gradient.GRADIENT_TYPE.RADIAL_GRADIENT: // $FlowFixMe this.target.renderRadialGradient(gradientBounds, gradient); break; } } } }, { key: 'renderBorder', value: function renderBorder(border, side, curvePoints) { this.target.drawShape((0, _Bounds.parsePathForBorder)(curvePoints, side), border.borderColor); } }, { key: 'renderStack', value: function renderStack(stack) { var _this4 = this; if (stack.container.isVisible()) { var _opacity = stack.getOpacity(); if (_opacity !== this._opacity) { this.target.setOpacity(stack.getOpacity()); this._opacity = _opacity; } var _transform = stack.container.style.transform; if (_transform !== null) { this.target.transform(stack.container.bounds.left + _transform.transformOrigin[0].value, stack.container.bounds.top + _transform.transformOrigin[1].value, _transform.transform, function () { return _this4.renderStackContent(stack); }); } else { this.renderStackContent(stack); } } } }, { key: 'renderStackContent', value: function renderStackContent(stack) { var _splitStackingContext = splitStackingContexts(stack), _splitStackingContext2 = _slicedToArray(_splitStackingContext, 5), negativeZIndex = _splitStackingContext2[0], zeroOrAutoZIndexOrTransformedOrOpacity = _splitStackingContext2[1], positiveZIndex = _splitStackingContext2[2], nonPositionedFloats = _splitStackingContext2[3], nonPositionedInlineLevel = _splitStackingContext2[4]; var _splitDescendants = splitDescendants(stack), _splitDescendants2 = _slicedToArray(_splitDescendants, 2), inlineLevel = _splitDescendants2[0], nonInlineLevel = _splitDescendants2[1]; // https://www.w3.org/TR/css-position-3/#painting-order // 1. the background and borders of the element forming the stacking context. this.renderNodeBackgroundAndBorders(stack.container); // 2. the child stacking contexts with negative stack levels (most negative first). negativeZIndex.sort(sortByZIndex).forEach(this.renderStack, this); // 3. For all its in-flow, non-positioned, block-level descendants in tree order: this.renderNodeContent(stack.container); nonInlineLevel.forEach(this.renderNode, this); // 4. All non-positioned floating descendants, in tree order. For each one of these, // treat the element as if it created a new stacking context, but any positioned descendants and descendants // which actually create a new stacking context should be considered part of the parent stacking context, // not this new one. nonPositionedFloats.forEach(this.renderStack, this); // 5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks. nonPositionedInlineLevel.forEach(this.renderStack, this); inlineLevel.forEach(this.renderNode, this); // 6. All positioned, opacity or transform descendants, in tree order that fall into the following categories: // All positioned descendants with 'z-index: auto' or 'z-index: 0', in tree order. // For those with 'z-index: auto', treat the element as if it created a new stacking context, // but any positioned descendants and descendants which actually create a new stacking context should be // considered part of the parent stacking context, not this new one. For those with 'z-index: 0', // treat the stacking context generated atomically. // // All opacity descendants with opacity less than 1 // // All transform descendants with transform other than none zeroOrAutoZIndexOrTransformedOrOpacity.forEach(this.renderStack, this); // 7. Stacking contexts formed by positioned descendants with z-indices greater than or equal to 1 in z-index // order (smallest first) then tree order. positiveZIndex.sort(sortByZIndex).forEach(this.renderStack, this); } }, { key: 'render', value: function render(stack) { var _this5 = this; if (this.options.backgroundColor) { this.target.rectangle(this.options.x, this.options.y, this.options.width, this.options.height, this.options.backgroundColor); } this.renderStack(stack); var target = this.target.getTarget(); if (process.env.NODE_ENV !== 'production') { return target.then(function (output) { _this5.options.logger.log('Render completed'); return output; }); } return target; } }]); return Renderer; }(); exports.default = Renderer; var splitDescendants = function splitDescendants(stack) { var inlineLevel = []; var nonInlineLevel = []; var length = stack.children.length; for (var i = 0; i < length; i++) { var child = stack.children[i]; if (child.isInlineLevel()) { inlineLevel.push(child); } else { nonInlineLevel.push(child); } } return [inlineLevel, nonInlineLevel]; }; var splitStackingContexts = function splitStackingContexts(stack) { var negativeZIndex = []; var zeroOrAutoZIndexOrTransformedOrOpacity = []; var positiveZIndex = []; var nonPositionedFloats = []; var nonPositionedInlineLevel = []; var length = stack.contexts.length; for (var i = 0; i < length; i++) { var child = stack.contexts[i]; if (child.container.isPositioned() || child.container.style.opacity < 1 || child.container.isTransformed()) { if (child.container.style.zIndex.order < 0) { negativeZIndex.push(child); } else if (child.container.style.zIndex.order > 0) { positiveZIndex.push(child); } else { zeroOrAutoZIndexOrTransformedOrOpacity.push(child); } } else { if (child.container.isFloating()) { nonPositionedFloats.push(child); } else { nonPositionedInlineLevel.push(child); } } } return [negativeZIndex, zeroOrAutoZIndexOrTransformedOrOpacity, positiveZIndex, nonPositionedFloats, nonPositionedInlineLevel]; }; var sortByZIndex = function sortByZIndex(a, b) { if (a.container.style.zIndex.order > b.container.style.zIndex.order) { return 1; } else if (a.container.style.zIndex.order < b.container.style.zIndex.order) { return -1; } return a.container.index > b.container.index ? 1 : -1; };