"use strict"; var _html2canvas = {}, previousElement, computedCSS, html2canvas; _html2canvas.Util = {}; _html2canvas.Util.log = function(a) { if (_html2canvas.logging && window.console && window.console.log) { window.console.log(a); } }; _html2canvas.Util.trimText = (function(isNative){ return function(input) { return isNative ? isNative.apply(input) : ((input || '') + '').replace( /^\s+|\s+$/g , '' ); }; })(String.prototype.trim); _html2canvas.Util.asFloat = function(v) { return parseFloat(v); }; (function() { // TODO: support all possible length values var TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g; var TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g; _html2canvas.Util.parseTextShadows = function (value) { if (!value || value === 'none') { return []; } // find multiple shadow declarations var shadows = value.match(TEXT_SHADOW_PROPERTY), results = []; for (var i = 0; shadows && (i < shadows.length); i++) { var s = shadows[i].match(TEXT_SHADOW_VALUES); results.push({ color: s[0], offsetX: s[1] ? s[1].replace('px', '') : 0, offsetY: s[2] ? s[2].replace('px', '') : 0, blur: s[3] ? s[3].replace('px', '') : 0 }); } return results; }; })(); _html2canvas.Util.parseBackgroundImage = function (value) { var whitespace = ' \r\n\t', method, definition, prefix, prefix_i, block, results = [], c, mode = 0, numParen = 0, quote, args; var appendResult = function(){ if(method) { if(definition.substr( 0, 1 ) === '"') { definition = definition.substr( 1, definition.length - 2 ); } if(definition) { args.push(definition); } if(method.substr( 0, 1 ) === '-' && (prefix_i = method.indexOf( '-', 1 ) + 1) > 0) { prefix = method.substr( 0, prefix_i); method = method.substr( prefix_i ); } results.push({ prefix: prefix, method: method.toLowerCase(), value: block, args: args }); } args = []; //for some odd reason, setting .length = 0 didn't work in safari method = prefix = definition = block = ''; }; appendResult(); for(var i = 0, ii = value.length; i -1){ continue; } switch(c) { case '"': if(!quote) { quote = c; } else if(quote === c) { quote = null; } break; case '(': if(quote) { break; } else if(mode === 0) { mode = 1; block += c; continue; } else { numParen++; } break; case ')': if(quote) { break; } else if(mode === 1) { if(numParen === 0) { mode = 0; block += c; appendResult(); continue; } else { numParen--; } } break; case ',': if(quote) { break; } else if(mode === 0) { appendResult(); continue; } else if (mode === 1) { if(numParen === 0 && !method.match(/^url$/i)) { args.push(definition); definition = ''; block += c; continue; } } break; } block += c; if(mode === 0) { method += c; } else { definition += c; } } appendResult(); return results; }; _html2canvas.Util.Bounds = function (element) { var clientRect, bounds = {}; if (element.getBoundingClientRect){ clientRect = element.getBoundingClientRect(); // TODO add scroll position to bounds, so no scrolling of window necessary bounds.top = clientRect.top; bounds.bottom = clientRect.bottom || (clientRect.top + clientRect.height); bounds.left = clientRect.left; bounds.width = element.offsetWidth; bounds.height = element.offsetHeight; } return bounds; }; // TODO ideally, we'd want everything to go through this function instead of Util.Bounds, // but would require further work to calculate the correct positions for elements with offsetParents _html2canvas.Util.OffsetBounds = function (element) { var parent = element.offsetParent ? _html2canvas.Util.OffsetBounds(element.offsetParent) : {top: 0, left: 0}; return { top: element.offsetTop + parent.top, bottom: element.offsetTop + element.offsetHeight + parent.top, left: element.offsetLeft + parent.left, width: element.offsetWidth, height: element.offsetHeight }; }; function toPX(element, attribute, value ) { var rsLeft = element.runtimeStyle && element.runtimeStyle[attribute], left, style = element.style; // Check if we are not dealing with pixels, (Opera has issues with this) // Ported from jQuery css.js // From the awesome hack by Dean Edwards // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 // If we're not dealing with a regular pixel number // but a number that has a weird ending, we need to convert it to pixels if ( !/^-?[0-9]+\.?[0-9]*(?:px)?$/i.test( value ) && /^-?\d/.test(value) ) { // Remember the original values left = style.left; // Put in the new values to get a computed value out if (rsLeft) { element.runtimeStyle.left = element.currentStyle.left; } style.left = attribute === "fontSize" ? "1em" : (value || 0); value = style.pixelLeft + "px"; // Revert the changed values style.left = left; if (rsLeft) { element.runtimeStyle.left = rsLeft; } } if (!/^(thin|medium|thick)$/i.test(value)) { return Math.round(parseFloat(value)) + "px"; } return value; } function asInt(val) { return parseInt(val, 10); } function parseBackgroundSizePosition(value, element, attribute, index) { value = (value || '').split(','); value = value[index || 0] || value[0] || 'auto'; value = _html2canvas.Util.trimText(value).split(' '); if(attribute === 'backgroundSize' && (value[0] && value[0].match(/^(cover|contain|auto)$/))) { return value; } else { value[0] = (value[0].indexOf( "%" ) === -1) ? toPX(element, attribute + "X", value[0]) : value[0]; if(value[1] === undefined) { if(attribute === 'backgroundSize') { value[1] = 'auto'; return value; } else { // IE 9 doesn't return double digit always value[1] = value[0]; } } value[1] = (value[1].indexOf("%") === -1) ? toPX(element, attribute + "Y", value[1]) : value[1]; } return value; } _html2canvas.Util.getCSS = function (element, attribute, index) { if (previousElement !== element) { computedCSS = document.defaultView.getComputedStyle(element, null); } var value = computedCSS[attribute]; if (/^background(Size|Position)$/.test(attribute)) { return parseBackgroundSizePosition(value, element, attribute, index); } else if (/border(Top|Bottom)(Left|Right)Radius/.test(attribute)) { var arr = value.split(" "); if (arr.length <= 1) { arr[1] = arr[0]; } return arr.map(asInt); } return value; }; _html2canvas.Util.resizeBounds = function( current_width, current_height, target_width, target_height, stretch_mode ){ var target_ratio = target_width / target_height, current_ratio = current_width / current_height, output_width, output_height; if(!stretch_mode || stretch_mode === 'auto') { output_width = target_width; output_height = target_height; } else if(target_ratio < current_ratio ^ stretch_mode === 'contain') { output_height = target_height; output_width = target_height * current_ratio; } else { output_width = target_width; output_height = target_width / current_ratio; } return { width: output_width, height: output_height }; }; _html2canvas.Util.BackgroundPosition = function(element, bounds, image, imageIndex, backgroundSize ) { var backgroundPosition = _html2canvas.Util.getCSS(element, 'backgroundPosition', imageIndex), leftPosition, topPosition; if (backgroundPosition.length === 1){ backgroundPosition = [backgroundPosition[0], backgroundPosition[0]]; } if (backgroundPosition[0].toString().indexOf("%") !== -1){ leftPosition = (bounds.width - (backgroundSize || image).width) * (parseFloat(backgroundPosition[0]) / 100); } else { leftPosition = parseInt(backgroundPosition[0], 10); } if (backgroundPosition[1] === 'auto') { topPosition = leftPosition / image.width * image.height; } else if (backgroundPosition[1].toString().indexOf("%") !== -1){ topPosition = (bounds.height - (backgroundSize || image).height) * parseFloat(backgroundPosition[1]) / 100; } else { topPosition = parseInt(backgroundPosition[1], 10); } if (backgroundPosition[0] === 'auto') { leftPosition = topPosition / image.height * image.width; } return {left: leftPosition, top: topPosition}; }; _html2canvas.Util.BackgroundSize = function(element, bounds, image, imageIndex) { var backgroundSize = _html2canvas.Util.getCSS(element, 'backgroundSize', imageIndex), width, height; if (backgroundSize.length === 1){ backgroundSize = [backgroundSize[0], backgroundSize[0]]; } if (backgroundSize[0].toString().indexOf("%") !== -1){ width = bounds.width * parseFloat(backgroundSize[0]) / 100; } else if(backgroundSize[0] === 'auto') { width = image.width; } else { if (/contain|cover/.test(backgroundSize[0])) { var resized = _html2canvas.Util.resizeBounds(image.width, image.height, bounds.width, bounds.height, backgroundSize[0]); return {width: resized.width, height: resized.height}; } else { width = parseInt(backgroundSize[0], 10); } } if(backgroundSize[1] === 'auto') { height = width / image.width * image.height; } else if (backgroundSize[1].toString().indexOf("%") !== -1){ height = bounds.height * parseFloat(backgroundSize[1]) / 100; } else { height = parseInt(backgroundSize[1],10); } if (backgroundSize[0] === 'auto') { width = height / image.height * image.width; } return {width: width, height: height}; }; _html2canvas.Util.Extend = function (options, defaults) { for (var key in options) { if (options.hasOwnProperty(key)) { defaults[key] = options[key]; } } return defaults; }; /* * Derived from jQuery.contents() * Copyright 2010, John Resig * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license */ _html2canvas.Util.Children = function( elem ) { var children; try { children = (elem.nodeName && elem.nodeName.toUpperCase() === "IFRAME") ? elem.contentDocument || elem.contentWindow.document : (function(array) { var ret = []; if (array !== null) { (function(first, second ) { var i = first.length, j = 0; if (typeof second.length === "number") { for (var l = second.length; j < l; j++) { first[i++] = second[j]; } } else { while (second[j] !== undefined) { first[i++] = second[j++]; } } first.length = i; return first; })(ret, array); } return ret; })(elem.childNodes); } catch (ex) { _html2canvas.Util.log("html2canvas.Util.Children failed with exception: " + ex.message); children = []; } return children; }; _html2canvas.Util.isTransparent = function(backgroundColor) { return (!backgroundColor || backgroundColor === "transparent" || backgroundColor === "rgba(0, 0, 0, 0)"); };