Compare commits

...

23 Commits

Author SHA1 Message Date
Niklas von Hertzen
2a2ad9bb65 0.5.0-beta1 2015-10-19 01:00:58 +03:00
Niklas von Hertzen
81e60975cc Update build/deploy workflow 2015-10-19 01:00:04 +03:00
Niklas von Hertzen
a0669300c4 Update grunt-mocha-phantomjs to 2.0.0 2015-10-18 23:58:10 +03:00
Niklas von Hertzen
ba9758cf14 Reformat mocha text shadow test names 2015-10-18 23:57:55 +03:00
Niklas von Hertzen
aa05241ff8 Fix gradient tests 2015-10-18 23:57:41 +03:00
Niklas von Hertzen
5b4a6c26ee Add another border-radius test 2015-10-18 23:15:51 +03:00
Niklas von Hertzen
364a8aac1c Merge remote-tracking branch 'origin/pr/645' 2015-10-18 23:15:12 +03:00
Niklas von Hertzen
46078acf71 Fix #688 fatal exception on unmatched color stop 2015-10-18 16:51:53 +03:00
Niklas von Hertzen
4b37909f09 Fix support for requirejs/amd 2015-08-30 02:27:38 +03:00
hyojin.kwak
90f9eeba83 Fix #599 2015-06-10 16:13:17 +09:00
Niklas von Hertzen
98ee30643a Fix iOS scrolling issue on clone 2015-03-30 00:58:50 +03:00
Niklas von Hertzen
a49c3a2320 Correctly handle named colors in gradients 2015-03-29 23:20:17 +03:00
Niklas von Hertzen
4b80102e77 Merge pull request #545 from cornedor/ie-transforms
Transform matrix for IE
2015-03-08 01:03:22 +02:00
Corné Dorrestijn
9201cf7e95 Accept matrix3d and convert it 2015-03-05 15:52:23 +01:00
Niklas von Hertzen
c2baf42145 Fix fail on transparent colors in linear gradients 2015-03-01 17:43:18 +02:00
Niklas von Hertzen
d9a9615ed7 Add acid2 test case 2015-03-01 17:12:09 +02:00
Niklas von Hertzen
585a96a918 Preserve scrolling positions of nodes on clone (#511) 2015-02-28 16:51:52 +02:00
Niklas von Hertzen
9a0d43d60b Bump v0.5.0-alpha2 2015-02-03 22:11:20 +02:00
Niklas von Hertzen
3671de81f9 Fix module name casing 2015-02-03 21:39:57 +02:00
Niklas von Hertzen
f3b6df267e Switch build to use browserify (#502) 2015-02-03 21:34:05 +02:00
Niklas von Hertzen
60619dca72 Fix #517 2015-01-26 22:55:10 +02:00
Niklas von Hertzen
ed299b3db1 Remove dead code 2015-01-20 19:51:52 +02:00
Niklas von Hertzen
c7e484af89 Add npm bower postpublish script 2015-01-19 23:52:50 +02:00
58 changed files with 4373 additions and 1331 deletions

2
.gitignore vendored
View File

@@ -1,6 +1,7 @@
/nbproject/
image.jpg
/.project
dist/
/.settings/
node_modules/
.envrc
@@ -9,3 +10,4 @@ node_modules/
*.iml
.idea/
.DS_Store
npm-debug.log

3
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "src/fabric"]
path = src/fabric
url = https://github.com/kangax/fabric.js.git
[submodule "src/punycode"]
path = src/punycode
url = https://github.com/bestiejs/punycode.js.git

View File

@@ -15,6 +15,5 @@
"globals": {
"jQuery": true
},
"predef": ["NodeParser", "NodeContainer", "Color", "StackingContext", "TextContainer", "PseudoElementContainer", "ImageLoader", "CanvasRenderer", "Renderer", "Support", "bind", "Promise", "getBounds", "offsetBounds", "XHR",
"ImageContainer", "ProxyImageContainer", "DummyImageContainer", "Font", "FontMetrics", "GradientContainer", "LinearGradientContainer", "WebkitGradientContainer", "SVGContainer", "SVGNodeContainer", "FrameContainer", "html2canvas", "log", "smallImage", "parseBackgrounds", "loadUrlDocument", "decode64", "Proxy", "ProxyURL"]
"predef": ["-Promise", "define"]
}

5
.npmignore Normal file
View File

@@ -0,0 +1,5 @@
tests/
examples/
Gruntfile.js
bower.json
src/

View File

@@ -1,21 +1,29 @@
---
language: node_js
node_js:
- '0.10'
env:
global:
- secure: "eW41gIqOizwO4pTgWnAAbW75AP7F+CK9qfSed/fSh4sJ9HWMIY1YRIaY8gjr+6jV/f7XVHcXuym6ZxgINYSkVKbF1JKxBJNLOXtSgNbVHSic58pYFvUjwxIBI9aPig9uux1+DbnpWqXFDTcACJSevQZE0xwmjdrSkDLgB0G34v8="
- secure: "Y2Av+Gd3z9uQEB36GwdOOuGka0hx0/HeitASEo59z934O8RxnmN9eNTXS7dDT3XtKtwxIyLTOEpS7qlRdWahH28hr/dS4xJj6ao58C+1xMcDs6NAPGmDxUlcJWpcGEsnjmXjQCc3fBioSTdpIBrK/gdvgpNh77UKG74Sk7Z+YGk="
- secure: "YI+YbTOGf2x4fPMKW+KhJiZWswoXT6xOKGwLfsQsVwmFX1LerJouil5D5iYOQuL4FE3pNaoJSNakIsokJQuGKJMmnPc8rdhMZuBJBk6MRghurE2Xe9qBHfuUBPlfD61nARESm4WDcyMwM0QVYaOKeY6aIpZ91qbUbyc60EEx3C4="
- secure: eW41gIqOizwO4pTgWnAAbW75AP7F+CK9qfSed/fSh4sJ9HWMIY1YRIaY8gjr+6jV/f7XVHcXuym6ZxgINYSkVKbF1JKxBJNLOXtSgNbVHSic58pYFvUjwxIBI9aPig9uux1+DbnpWqXFDTcACJSevQZE0xwmjdrSkDLgB0G34v8=
- secure: Y2Av+Gd3z9uQEB36GwdOOuGka0hx0/HeitASEo59z934O8RxnmN9eNTXS7dDT3XtKtwxIyLTOEpS7qlRdWahH28hr/dS4xJj6ao58C+1xMcDs6NAPGmDxUlcJWpcGEsnjmXjQCc3fBioSTdpIBrK/gdvgpNh77UKG74Sk7Z+YGk=
- secure: YI+YbTOGf2x4fPMKW+KhJiZWswoXT6xOKGwLfsQsVwmFX1LerJouil5D5iYOQuL4FE3pNaoJSNakIsokJQuGKJMmnPc8rdhMZuBJBk6MRghurE2Xe9qBHfuUBPlfD61nARESm4WDcyMwM0QVYaOKeY6aIpZ91qbUbyc60EEx3C4=
addons:
sauce_connect: true
before_script:
- npm install -g grunt-cli
- npm install -g uglify-js
- npm install -g grunt-cli
- npm install -g uglify-js
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/2b007d4f86de89588804
- https://webhooks.gitter.im/e/2b007d4f86de89588804
on_success: always
on_failure: always
on_start: false
deploy:
- provider: npm
email: niklasvh@gmail.com
api_key:
secure: dot+HzIe3thKep5mz5pyNYQV1ZYiGlVQAWScmfYh75AtOCJQJGvvw1alwRZDL0Ykn/7LeftZik845INn8Al8h4OEUQyuq2WmybZ5zn7PsLXRes7FtlJeYERO79bV5P3aV4vq4QoaZkPB5jQ98CmgQ2/9xPB+1ogNd7fRfUpSvSI=
on:
tags: true
branch: master
repo: niklasvh/html2canvas

View File

@@ -1,5 +1,9 @@
### Changelog ###
v0.5.0-alpha2 - 3.2.2015
* Switch to using browserify for building
* Fix (#517) Chrome stretches background images with 'auto' or single attributes
v0.5.0-alpha - 19.1.2015
* Complete rewrite of library
* Switched interface to return Promise

View File

@@ -8,9 +8,7 @@ module.exports = function(grunt) {
banner: '/*\n <%= pkg.title || pkg.name %> <%= pkg.version %>' +
'<%= pkg.homepage ? " <" + pkg.homepage + ">" : "" %>' + '\n' +
' Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>' +
'\n\n Released under <%= _.pluck(pkg.licenses, "type").join(", ") %> License\n*/\n',
pre: '\n(function(window, document, exports, global, define, undefined){\n\n',
post: '\n}).call({}, typeof(window) !== "undefined" ? window : undefined, typeof(document) !== "undefined" ? document : undefined);'
'\n\n Released under <%= _.pluck(pkg.licenses, "type").join(", ") %> License\n*/\n'
};
var browsers = {
@@ -59,16 +57,15 @@ module.exports = function(grunt) {
pkg: grunt.file.readJSON('package.json'),
concat: {
browserify: {
dist: {
src: [
'src/promise.js', 'src/fallback.js', 'src/punycode/punycode.js', 'src/core.js', 'src/*.js', 'src/renderers/*.js'
],
nonull: true,
src: ['src/core.js'],
dest: 'dist/<%= pkg.name %>.js',
options:{
banner: meta.banner + meta.pre,
footer: meta.post
options: {
browserifyOptions: {
standalone: 'html2canvas'
},
banner: meta.banner
}
},
svg: {
@@ -77,8 +74,10 @@ module.exports = function(grunt) {
],
dest: 'dist/<%= pkg.name %>.svg.js',
options:{
banner: meta.banner + '\n(function(window, document, exports, undefined){\n\n',
footer: '\n}).call({}, window, document, html2canvas);'
browserifyOptions: {
standalone: 'html2canvas.svg'
},
banner: meta.banner
}
}
},
@@ -149,11 +148,11 @@ module.exports = function(grunt) {
},
uglify: {
dist: {
src: ['<%= concat.dist.dest %>'],
src: ['<%= browserify.dist.dest %>'],
dest: 'dist/<%= pkg.name %>.min.js'
},
svg: {
src: ['<%= concat.svg.dest %>'],
src: ['<%= browserify.svg.dest %>'],
dest: 'dist/<%= pkg.name %>.svg.min.js'
},
options: {
@@ -165,7 +164,7 @@ module.exports = function(grunt) {
tasks: ['jshint', 'build']
},
jshint: {
all: ['src/*.js', 'src/renderers/*.js', '!src/promise.js'],
all: ['src/*.js', 'src/renderers/*.js'],
options: grunt.file.readJSON('./.jshintrc')
},
mochacli: {
@@ -204,9 +203,9 @@ module.exports = function(grunt) {
});
});
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-mocha-phantomjs');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-connect');
@@ -214,7 +213,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-mocha-cli');
grunt.registerTask('server', ['connect:cors', 'connect:proxy', 'connect:altServer', 'connect:server']);
grunt.registerTask('build', ['execute', 'concat', 'uglify']);
grunt.registerTask('build', ['execute', 'browserify', 'uglify']);
grunt.registerTask('default', ['jshint', 'build', 'mochacli', 'connect:altServer', 'mocha_phantomjs']);
grunt.registerTask('travis', ['jshint', 'build', 'connect:altServer', 'connect:ci', 'connect:proxy', 'connect:cors', 'mocha_phantomjs', 'webdriver']);

2536
dist/html2canvas.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

1575
dist/html2canvas.svg.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
module.exports = require('./dist/html2canvas').html2canvas;

View File

@@ -2,8 +2,8 @@
"title": "html2canvas",
"name": "html2canvas",
"description": "Screenshots with JavaScript",
"main": "main.js",
"version": "0.5.0-alpha1",
"main": "dist/html2canvas.js",
"version": "0.5.0-beta1",
"author": {
"name": "Niklas von Hertzen",
"email": "niklasvh@gmail.com",
@@ -12,7 +12,9 @@
"engines": {
"node": ">=0.10.0"
},
"dependencies": {},
"dependencies": {
"es6-promise": "^2.0.1"
},
"repository": {
"type": "git",
"url": "git@github.com:niklasvh/html2canvas.git"
@@ -23,23 +25,26 @@
"devDependencies": {
"base64-arraybuffer": ">= 0.1.0",
"bluebird": "^2.7.1",
"bower": "^1.3.12",
"grunt": "^0.4.5",
"grunt-contrib-concat": "^0.5.0",
"grunt-browserify": "^3.3.0",
"grunt-contrib-connect": "^0.8.0",
"grunt-contrib-jshint": "^0.10.0",
"grunt-contrib-uglify": "^0.6.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-execute": "^0.2.2",
"grunt-mocha-cli": "^1.12.0",
"grunt-mocha-phantomjs": "^0.6.0",
"grunt-mocha-phantomjs": "^2.0.0",
"html2canvas-proxy": "0.0.5",
"humanize-duration": "^2.0.1",
"lodash": "^2.4.1",
"png-js": ">= 0.1.1",
"requirejs": "^2.1.20",
"wd": "^0.2.21"
},
"scripts": {
"test": "grunt travis --verbose"
"test": "grunt travis --verbose",
"postpublish": "bower register html2canvas git://github.com/niklasvh/html2canvas.git"
},
"homepage": "http://html2canvas.hertzen.com",
"licenses": [

105
src/clone.js Normal file
View File

@@ -0,0 +1,105 @@
var log = require('./log');
var Promise = require('./promise');
function restoreOwnerScroll(ownerDocument, x, y) {
if (ownerDocument.defaultView && (x !== ownerDocument.defaultView.pageXOffset || y !== ownerDocument.defaultView.pageYOffset)) {
ownerDocument.defaultView.scrollTo(x, y);
}
}
function cloneCanvasContents(canvas, clonedCanvas) {
try {
if (clonedCanvas) {
clonedCanvas.width = canvas.width;
clonedCanvas.height = canvas.height;
clonedCanvas.getContext("2d").putImageData(canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height), 0, 0);
}
} catch(e) {
log("Unable to copy canvas content from", canvas, e);
}
}
function cloneNode(node, javascriptEnabled) {
var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);
var child = node.firstChild;
while(child) {
if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
clone.appendChild(cloneNode(child, javascriptEnabled));
}
child = child.nextSibling;
}
if (node.nodeType === 1) {
clone._scrollTop = node.scrollTop;
clone._scrollLeft = node.scrollLeft;
if (node.nodeName === "CANVAS") {
cloneCanvasContents(node, clone);
} else if (node.nodeName === "TEXTAREA" || node.nodeName === "SELECT") {
clone.value = node.value;
}
}
return clone;
}
function initNode(node) {
if (node.nodeType === 1) {
node.scrollTop = node._scrollTop;
node.scrollLeft = node._scrollLeft;
var child = node.firstChild;
while(child) {
initNode(child);
child = child.nextSibling;
}
}
}
module.exports = function(ownerDocument, containerDocument, width, height, options, x ,y) {
var documentElement = cloneNode(ownerDocument.documentElement, options.javascriptEnabled);
var container = containerDocument.createElement("iframe");
container.className = "html2canvas-container";
container.style.visibility = "hidden";
container.style.position = "fixed";
container.style.left = "-10000px";
container.style.top = "0px";
container.style.border = "0";
container.width = width;
container.height = height;
container.scrolling = "no"; // ios won't scroll without it
containerDocument.body.appendChild(container);
return new Promise(function(resolve) {
var documentClone = container.contentWindow.document;
/* Chrome doesn't detect relative background-images assigned in inline <style> sheets when fetched through getComputedStyle
if window url is about:blank, we can assign the url to current by writing onto the document
*/
container.contentWindow.onload = container.onload = function() {
var interval = setInterval(function() {
if (documentClone.body.childNodes.length > 0) {
initNode(documentClone.documentElement);
clearInterval(interval);
if (options.type === "view") {
container.contentWindow.scrollTo(x, y);
if ((/(iPad|iPhone|iPod)/g).test(navigator.userAgent) && (container.contentWindow.scrollY !== y || container.contentWindow.scrollX !== x)) {
documentClone.documentElement.style.top = (-y) + "px";
documentClone.documentElement.style.left = (-x) + "px";
documentClone.documentElement.style.position = 'absolute';
}
}
resolve(container);
}
}, 50);
};
documentClone.open();
documentClone.write("<!DOCTYPE html><html></html>");
// Chrome scrolls the parent document for some reason after the write to the cloned window???
restoreOwnerScroll(ownerDocument, x, y);
documentClone.replaceChild(documentClone.adoptNode(documentElement), documentClone.documentElement);
documentClone.close();
});
};

View File

@@ -268,3 +268,4 @@ var colors = {
"yellowgreen": [154, 205, 50]
};
module.exports = Color;

View File

@@ -1,9 +1,19 @@
var Promise = require('./promise');
var Support = require('./support');
var CanvasRenderer = require('./renderers/canvas');
var ImageLoader = require('./imageloader');
var NodeParser = require('./nodeparser');
var NodeContainer = require('./nodecontainer');
var log = require('./log');
var utils = require('./utils');
var createWindowClone = require('./clone');
var loadUrlDocument = require('./proxy').loadUrlDocument;
var getBounds = utils.getBounds;
var html2canvasNodeAttribute = "data-html2canvas-node";
var html2canvasCanvasCloneAttribute = "data-html2canvas-canvas-clone";
var html2canvasCanvasCloneIndex = 0;
var html2canvasCloneIndex = 0;
window.html2canvas = function(nodeList, options) {
function html2canvas(nodeList, options) {
var index = html2canvasCloneIndex++;
options = options || {};
if (options.logging) {
@@ -39,10 +49,25 @@ window.html2canvas = function(nodeList, options) {
}
return canvas;
});
};
}
window.html2canvas.punycode = this.punycode;
window.html2canvas.proxy = {};
html2canvas.Promise = Promise;
html2canvas.CanvasRenderer = CanvasRenderer;
html2canvas.NodeContainer = NodeContainer;
html2canvas.log = log;
html2canvas.utils = utils;
var html2canvasExport = (typeof(document) === "undefined" || typeof(Object.create) !== "function" || typeof(document.createElement("canvas").getContext) !== "function") ? function() {
return Promise.reject("No canvas support");
} : html2canvas;
module.exports = html2canvasExport;
if (typeof(define) === 'function' && define.amd) {
define('html2canvas', [], function() {
return html2canvasExport;
});
}
function renderDocument(document, options, windowWidth, windowHeight, html2canvasIndex) {
return createWindowClone(document, document, windowWidth, windowHeight, options, document.defaultView.pageXOffset, document.defaultView.pageYOffset).then(function(container) {
@@ -122,164 +147,6 @@ function documentHeight (doc) {
);
}
function smallImage() {
return "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
}
function isIE9() {
return document.documentMode && document.documentMode <= 9;
}
// https://github.com/niklasvh/html2canvas/issues/503
function cloneNodeIE9(node, javascriptEnabled) {
var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);
var child = node.firstChild;
while(child) {
if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
clone.appendChild(cloneNodeIE9(child, javascriptEnabled));
}
child = child.nextSibling;
}
return clone;
}
function createWindowClone(ownerDocument, containerDocument, width, height, options, x ,y) {
labelCanvasElements(ownerDocument);
var documentElement = isIE9() ? cloneNodeIE9(ownerDocument.documentElement, options.javascriptEnabled) : ownerDocument.documentElement.cloneNode(true);
var container = containerDocument.createElement("iframe");
container.className = "html2canvas-container";
container.style.visibility = "hidden";
container.style.position = "fixed";
container.style.left = "-10000px";
container.style.top = "0px";
container.style.border = "0";
container.width = width;
container.height = height;
container.scrolling = "no"; // ios won't scroll without it
containerDocument.body.appendChild(container);
return new Promise(function(resolve) {
var documentClone = container.contentWindow.document;
cloneNodeValues(ownerDocument.documentElement, documentElement, "textarea");
cloneNodeValues(ownerDocument.documentElement, documentElement, "select");
/* Chrome doesn't detect relative background-images assigned in inline <style> sheets when fetched through getComputedStyle
if window url is about:blank, we can assign the url to current by writing onto the document
*/
container.contentWindow.onload = container.onload = function() {
var interval = setInterval(function() {
if (documentClone.body.childNodes.length > 0) {
cloneCanvasContents(ownerDocument, documentClone);
clearInterval(interval);
if (options.type === "view") {
container.contentWindow.scrollTo(x, y);
}
resolve(container);
}
}, 50);
};
documentClone.open();
documentClone.write("<!DOCTYPE html><html></html>");
// Chrome scrolls the parent document for some reason after the write to the cloned window???
restoreOwnerScroll(ownerDocument, x, y);
documentClone.replaceChild(options.javascriptEnabled === true ? documentClone.adoptNode(documentElement) : removeScriptNodes(documentClone.adoptNode(documentElement)), documentClone.documentElement);
documentClone.close();
});
}
function cloneNodeValues(document, clone, nodeName) {
var originalNodes = document.getElementsByTagName(nodeName);
var clonedNodes = clone.getElementsByTagName(nodeName);
var count = originalNodes.length;
for (var i = 0; i < count; i++) {
clonedNodes[i].value = originalNodes[i].value;
}
}
function restoreOwnerScroll(ownerDocument, x, y) {
if (ownerDocument.defaultView && (x !== ownerDocument.defaultView.pageXOffset || y !== ownerDocument.defaultView.pageYOffset)) {
ownerDocument.defaultView.scrollTo(x, y);
}
}
function loadUrlDocument(src, proxy, document, width, height, options) {
return new Proxy(src, proxy, window.document).then(documentFromHTML(src)).then(function(doc) {
return createWindowClone(doc, document, width, height, options, 0, 0);
});
}
function documentFromHTML(src) {
return function(html) {
var parser = new DOMParser(), doc;
try {
doc = parser.parseFromString(html, "text/html");
} catch(e) {
log("DOMParser not supported, falling back to createHTMLDocument");
doc = document.implementation.createHTMLDocument("");
try {
doc.open();
doc.write(html);
doc.close();
} catch(ee) {
log("createHTMLDocument write not supported, falling back to document.body.innerHTML");
doc.body.innerHTML = html; // ie9 doesnt support writing to documentElement
}
}
var b = doc.querySelector("base");
if (!b || !b.href.host) {
var base = doc.createElement("base");
base.href = src;
doc.head.insertBefore(base, doc.head.firstChild);
}
return doc;
};
}
function labelCanvasElements(ownerDocument) {
[].slice.call(ownerDocument.querySelectorAll("canvas"), 0).forEach(function(canvas) {
canvas.setAttribute(html2canvasCanvasCloneAttribute, "canvas-" + html2canvasCanvasCloneIndex++);
});
}
function cloneCanvasContents(ownerDocument, documentClone) {
[].slice.call(ownerDocument.querySelectorAll("[" + html2canvasCanvasCloneAttribute + "]"), 0).forEach(function(canvas) {
try {
var clonedCanvas = documentClone.querySelector('[' + html2canvasCanvasCloneAttribute + '="' + canvas.getAttribute(html2canvasCanvasCloneAttribute) + '"]');
if (clonedCanvas) {
clonedCanvas.width = canvas.width;
clonedCanvas.height = canvas.height;
clonedCanvas.getContext("2d").putImageData(canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height), 0, 0);
}
} catch(e) {
log("Unable to copy canvas content from", canvas, e);
}
canvas.removeAttribute(html2canvasCanvasCloneAttribute);
});
}
function removeScriptNodes(parent) {
[].slice.call(parent.childNodes, 0).filter(isElementNode).forEach(function(node) {
if (node.tagName === "SCRIPT") {
parent.removeChild(node);
} else {
removeScriptNodes(node);
}
});
return parent;
}
function isElementNode(node) {
return node.nodeType === Node.ELEMENT_NODE;
}
function absoluteUrl(url) {
var link = document.createElement("a");
link.href = url;

View File

@@ -1,3 +1,7 @@
var Promise = require('./promise');
var log = require('./log');
var smallImage = require('./utils').smallImage;
function DummyImageContainer(src) {
this.src = src;
log("DummyImageContainer for", src);
@@ -15,3 +19,5 @@ function DummyImageContainer(src) {
});
}
}
module.exports = DummyImageContainer;

View File

@@ -1,6 +0,0 @@
if (typeof(document) === "undefined" || typeof(Object.create) !== "function" || typeof(document.createElement("canvas").getContext) !== "function") {
(window || module.exports).html2canvas = function() {
return Promise.reject("No canvas support");
};
return;
}

View File

@@ -1,3 +1,5 @@
var smallImage = require('./utils').smallImage;
function Font(family, size) {
var container = document.createElement('div'),
img = document.createElement('img'),
@@ -46,3 +48,5 @@ function Font(family, size) {
this.lineWidth = 1;
this.middle = middle;
}
module.exports = Font;

View File

@@ -1,3 +1,5 @@
var Font = require('./font');
function FontMetrics() {
this.data = {};
}
@@ -8,3 +10,5 @@ FontMetrics.prototype.getMetrics = function(family, size) {
}
return this.data[family + "-" + size];
};
module.exports = FontMetrics;

View File

@@ -1,3 +1,8 @@
var utils = require('./utils');
var Promise = require('./promise');
var getBounds = utils.getBounds;
var loadUrlDocument = require('./proxy').loadUrlDocument;
function FrameContainer(container, sameOrigin, options) {
this.image = null;
this.src = container;
@@ -12,6 +17,7 @@ function FrameContainer(container, sameOrigin, options) {
resolve(container);
}
})).then(function(container) {
var html2canvas = require('./core');
return html2canvas(container.contentWindow.document.documentElement, {type: 'view', width: container.width, height: container.height, proxy: options.proxy, javascriptEnabled: options.javascriptEnabled, removeContainer: options.removeContainer, allowTaint: options.allowTaint, imageTimeout: options.imageTimeout / 2});
}).then(function(canvas) {
return self.image = canvas;
@@ -22,3 +28,5 @@ FrameContainer.prototype.proxyLoad = function(proxy, bounds, options) {
var container = this.src;
return loadUrlDocument(container.src, proxy, container.ownerDocument, bounds.width, bounds.height, options);
};
module.exports = FrameContainer;

View File

@@ -1,3 +1,5 @@
var Promise = require('./promise');
function GradientContainer(imageData) {
this.src = imageData.value;
this.colorStops = [];
@@ -13,3 +15,5 @@ GradientContainer.prototype.TYPES = {
LINEAR: 1,
RADIAL: 2
};
module.exports = GradientContainer;

View File

@@ -1,3 +1,5 @@
var Promise = require('./promise');
function ImageContainer(src, cors) {
this.src = src;
this.image = new Image();
@@ -15,3 +17,5 @@ function ImageContainer(src, cors) {
}
});
}
module.exports = ImageContainer;

View File

@@ -1,3 +1,15 @@
var Promise = require('./promise');
var log = require('./log');
var ImageContainer = require('./imagecontainer');
var DummyImageContainer = require('./dummyimagecontainer');
var ProxyImageContainer = require('./proxyimagecontainer');
var FrameContainer = require('./framecontainer');
var SVGContainer = require('./svgcontainer');
var SVGNodeContainer = require('./svgnodecontainer');
var LinearGradientContainer = require('./lineargradientcontainer');
var WebkitGradientContainer = require('./webkitgradientcontainer');
var bind = require('./utils').bind;
function ImageLoader(options, support) {
this.link = null;
this.options = options;
@@ -142,3 +154,5 @@ ImageLoader.prototype.timeout = function(container, timeout) {
});
return promise;
};
module.exports = ImageLoader;

View File

@@ -1,3 +1,8 @@
var GradientContainer = require('./gradientcontainer');
var Color = require('./color');
var COLOR_STOP_REGEXP = /^\s*(.*)\s*(\d{1,3})?(%|px)?$/;
function LinearGradientContainer(imageData) {
GradientContainer.apply(this, arguments);
this.type = this.TYPES.LINEAR;
@@ -38,13 +43,15 @@ function LinearGradientContainer(imageData) {
this.y1 = 1;
}
this.colorStops = imageData.args.slice(hasDirection ? 1 : 0).map(function(colorStop) {
var colorStopMatch = colorStop.match(this.stepRegExp);
return {
color: new Color(colorStopMatch[1]),
stop: colorStopMatch[3] === "%" ? colorStopMatch[2] / 100 : null
};
}, this);
this.colorStops = imageData.args.slice(hasDirection ? 1 : 0)
.map(function(colorStop) { return colorStop.match(COLOR_STOP_REGEXP);})
.filter(function(colorStopMatch) { return !!colorStopMatch;})
.map(function(colorStopMatch) {
return {
color: new Color(colorStopMatch[1]),
stop: colorStopMatch[3] === "%" ? colorStopMatch[2] / 100 : null
};
});
if (this.colorStops[0].stop === null) {
this.colorStops[0].stop = 0;
@@ -71,3 +78,5 @@ function LinearGradientContainer(imageData) {
LinearGradientContainer.prototype = Object.create(GradientContainer.prototype);
LinearGradientContainer.prototype.stepRegExp = /((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/;
module.exports = LinearGradientContainer;

View File

@@ -1,5 +1,5 @@
function log() {
module.exports = function() {
if (window.html2canvas.logging && window.console && window.console.log) {
Function.prototype.bind.call(window.console.log, (window.console)).apply(window.console, [(Date.now() - window.html2canvas.start) + "ms", "html2canvas:"].concat([].slice.call(arguments, 0)));
}
}
};

View File

@@ -1,3 +1,9 @@
var Color = require('./color');
var utils = require('./utils');
var getBounds = utils.getBounds;
var parseBackgrounds = utils.parseBackgrounds;
var offsetBounds = utils.offsetBounds;
function NodeContainer(node, parent) {
this.node = node;
this.parent = parent;
@@ -121,7 +127,7 @@ NodeContainer.prototype.cssList = function(property, index) {
value = value[index || 0] || value[0] || 'auto';
value = value.trim().split(' ');
if (value.length === 1) {
value = [value[0], value[0]];
value = [value[0], isPercentage(value[0]) ? 'auto' : value[0]];
}
return value;
};
@@ -252,7 +258,7 @@ NodeContainer.prototype.getValue = function() {
return value.length === 0 ? (this.node.placeholder || "") : value;
};
NodeContainer.prototype.MATRIX_PROPERTY = /(matrix)\((.+)\)/;
NodeContainer.prototype.MATRIX_PROPERTY = /(matrix|matrix3d)\((.+)\)/;
NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g;
NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;
NodeContainer.prototype.CLIP = /^rect\((\d+)px,? (\d+)px,? (\d+)px,? (\d+)px\)$/;
@@ -267,6 +273,11 @@ function parseMatrix(match) {
return match[2].split(",").map(function(s) {
return parseFloat(s.trim());
});
} else if (match && match[1] === "matrix3d") {
var matrix3d = match[2].split(",").map(function(s) {
return parseFloat(s.trim());
});
return [matrix3d[0], matrix3d[1], matrix3d[4], matrix3d[5], matrix3d[12], matrix3d[13]];
}
}
@@ -274,102 +285,6 @@ function isPercentage(value) {
return value.toString().indexOf("%") !== -1;
}
function parseBackgrounds(backgroundImage) {
var whitespace = ' \r\n\t',
method, definition, prefix, prefix_i, block, results = [],
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,
image: null
});
}
args = [];
method = prefix = definition = block = '';
};
args = [];
method = prefix = definition = block = '';
backgroundImage.split("").forEach(function(c) {
if (mode === 0 && whitespace.indexOf(c) > -1) {
return;
}
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;
return;
} else {
numParen++;
}
break;
case ')':
if (quote) {
break;
} else if(mode === 1) {
if(numParen === 0) {
mode = 0;
block += c;
appendResult();
return;
} else {
numParen--;
}
}
break;
case ',':
if (quote) {
break;
} else if(mode === 0) {
appendResult();
return;
} else if (mode === 1) {
if (numParen === 0 && !method.match(/^url$/i)) {
args.push(definition);
definition = '';
block += c;
return;
}
}
break;
}
block += c;
if (mode === 0) {
method += c;
} else {
definition += c;
}
});
appendResult();
return results;
}
function removePx(str) {
return str.replace("px", "");
}
@@ -378,31 +293,4 @@ function asFloat(str) {
return parseFloat(str);
}
function getBounds(node) {
if (node.getBoundingClientRect) {
var clientRect = node.getBoundingClientRect();
var width = node.offsetWidth == null ? clientRect.width : node.offsetWidth;
return {
top: clientRect.top,
bottom: clientRect.bottom || (clientRect.top + clientRect.height),
right: clientRect.left + width,
left: clientRect.left,
width: width,
height: node.offsetHeight == null ? clientRect.height : node.offsetHeight
};
}
return {};
}
function offsetBounds(node) {
var parent = node.offsetParent ? offsetBounds(node.offsetParent) : {top: 0, left: 0};
return {
top: node.offsetTop + parent.top,
bottom: node.offsetTop + node.offsetHeight + parent.top,
right: node.offsetLeft + parent.left + node.offsetWidth,
left: node.offsetLeft + parent.left,
width: node.offsetWidth,
height: node.offsetHeight
};
}
module.exports = NodeContainer;

View File

@@ -1,3 +1,18 @@
var log = require('./log');
var punycode = require('punycode');
var NodeContainer = require('./nodecontainer');
var TextContainer = require('./textcontainer');
var PseudoElementContainer = require('./pseudoelementcontainer');
var FontMetrics = require('./fontmetrics');
var Color = require('./color');
var Promise = require('./promise');
var StackingContext = require('./stackingcontext');
var utils = require('./utils');
var bind = utils.bind;
var getBounds = utils.getBounds;
var parseBackgrounds = utils.parseBackgrounds;
var offsetBounds = utils.offsetBounds;
function NodeParser(element, renderer, support, imageLoader, options) {
log("Starting NodeParser");
this.renderer = renderer;
@@ -418,9 +433,9 @@ NodeParser.prototype.paintFormValue = function(container) {
NodeParser.prototype.paintText = function(container) {
container.applyTextTransform();
var characters = window.html2canvas.punycode.ucs2.decode(container.node.data);
var characters = punycode.ucs2.decode(container.node.data);
var textList = (!this.options.letterRendering || noLetterSpacing(container)) && !hasUnicode(container.node.data) ? getWords(characters) : characters.map(function(character) {
return window.html2canvas.punycode.ucs2.encode([character]);
return punycode.ucs2.encode([character]);
});
var weight = container.parent.fontWeight();
@@ -602,14 +617,14 @@ function calculateCurvePoints(bounds, borderRadius, borders) {
width = bounds.width,
height = bounds.height,
tlh = borderRadius[0][0],
tlv = borderRadius[0][1],
trh = borderRadius[1][0],
trv = borderRadius[1][1],
brh = borderRadius[2][0],
brv = borderRadius[2][1],
blh = borderRadius[3][0],
blv = borderRadius[3][1];
tlh = borderRadius[0][0] < width / 2 ? borderRadius[0][0] : width / 2,
tlv = borderRadius[0][1] < height / 2 ? borderRadius[0][1] : height / 2,
trh = borderRadius[1][0] < width / 2 ? borderRadius[1][0] : width / 2,
trv = borderRadius[1][1] < height / 2 ? borderRadius[1][1] : height / 2,
brh = borderRadius[2][0] < width / 2 ? borderRadius[2][0] : width / 2,
brv = borderRadius[2][1] < height / 2 ? borderRadius[2][1] : height / 2,
blh = borderRadius[3][0] < width / 2 ? borderRadius[3][0] : width / 2,
blv = borderRadius[3][1] < height / 2 ? borderRadius[3][1] : height / 2;
var topWidth = width - trh,
rightHeight = height - brv,
@@ -793,12 +808,6 @@ function hasOpacity(container) {
return container.getOpacity() < 1;
}
function bind(callback, context) {
return function() {
return callback.apply(context, arguments);
};
}
function asInt(value) {
return parseInt(value, 10);
}
@@ -826,7 +835,7 @@ function getWords(characters) {
if (isWordBoundary(characters[i]) === onWordBoundary) {
word = characters.splice(0, i);
if (word.length) {
words.push(window.html2canvas.punycode.ucs2.encode(word));
words.push(punycode.ucs2.encode(word));
}
onWordBoundary =! onWordBoundary;
i = 0;
@@ -837,7 +846,7 @@ function getWords(characters) {
if (i >= characters.length) {
word = characters.splice(0, i);
if (word.length) {
words.push(window.html2canvas.punycode.ucs2.encode(word));
words.push(punycode.ucs2.encode(word));
}
}
}
@@ -857,3 +866,5 @@ function isWordBoundary(characterCode) {
function hasUnicode(string) {
return (/[^\u0000-\u00ff]/).test(string);
}
module.exports = NodeParser;

View File

@@ -1,22 +1 @@
/*!
* @overview es6-promise - a tiny implementation of Promises/A+.
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
* @license Licensed under MIT license
* See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
* @version 2.0.1
*/
(function(){function r(a,b){n[l]=a;n[l+1]=b;l+=2;2===l&&A()}function s(a){return"function"===typeof a}function F(){return function(){process.nextTick(t)}}function G(){var a=0,b=new B(t),c=document.createTextNode("");b.observe(c,{characterData:!0});return function(){c.data=a=++a%2}}function H(){var a=new MessageChannel;a.port1.onmessage=t;return function(){a.port2.postMessage(0)}}function I(){return function(){setTimeout(t,1)}}function t(){for(var a=0;a<l;a+=2)(0,n[a])(n[a+1]),n[a]=void 0,n[a+1]=void 0;
l=0}function p(){}function J(a,b,c,d){try{a.call(b,c,d)}catch(e){return e}}function K(a,b,c){r(function(a){var e=!1,f=J(c,b,function(c){e||(e=!0,b!==c?q(a,c):m(a,c))},function(b){e||(e=!0,g(a,b))});!e&&f&&(e=!0,g(a,f))},a)}function L(a,b){1===b.a?m(a,b.b):2===a.a?g(a,b.b):u(b,void 0,function(b){q(a,b)},function(b){g(a,b)})}function q(a,b){if(a===b)g(a,new TypeError("You cannot resolve a promise with itself"));else if("function"===typeof b||"object"===typeof b&&null!==b)if(b.constructor===a.constructor)L(a,
b);else{var c;try{c=b.then}catch(d){v.error=d,c=v}c===v?g(a,v.error):void 0===c?m(a,b):s(c)?K(a,b,c):m(a,b)}else m(a,b)}function M(a){a.f&&a.f(a.b);x(a)}function m(a,b){void 0===a.a&&(a.b=b,a.a=1,0!==a.e.length&&r(x,a))}function g(a,b){void 0===a.a&&(a.a=2,a.b=b,r(M,a))}function u(a,b,c,d){var e=a.e,f=e.length;a.f=null;e[f]=b;e[f+1]=c;e[f+2]=d;0===f&&a.a&&r(x,a)}function x(a){var b=a.e,c=a.a;if(0!==b.length){for(var d,e,f=a.b,g=0;g<b.length;g+=3)d=b[g],e=b[g+c],d?C(c,d,e,f):e(f);a.e.length=0}}function D(){this.error=
null}function C(a,b,c,d){var e=s(c),f,k,h,l;if(e){try{f=c(d)}catch(n){y.error=n,f=y}f===y?(l=!0,k=f.error,f=null):h=!0;if(b===f){g(b,new TypeError("A promises callback cannot return that same promise."));return}}else f=d,h=!0;void 0===b.a&&(e&&h?q(b,f):l?g(b,k):1===a?m(b,f):2===a&&g(b,f))}function N(a,b){try{b(function(b){q(a,b)},function(b){g(a,b)})}catch(c){g(a,c)}}function k(a,b,c,d){this.n=a;this.c=new a(p,d);this.i=c;this.o(b)?(this.m=b,this.d=this.length=b.length,this.l(),0===this.length?m(this.c,
this.b):(this.length=this.length||0,this.k(),0===this.d&&m(this.c,this.b))):g(this.c,this.p())}function h(a){O++;this.b=this.a=void 0;this.e=[];if(p!==a){if(!s(a))throw new TypeError("You must pass a resolver function as the first argument to the promise constructor");if(!(this instanceof h))throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");N(this,a)}}var E=Array.isArray?Array.isArray:function(a){return"[object Array]"===
Object.prototype.toString.call(a)},l=0,w="undefined"!==typeof window?window:{},B=w.MutationObserver||w.WebKitMutationObserver,w="undefined"!==typeof Uint8ClampedArray&&"undefined"!==typeof importScripts&&"undefined"!==typeof MessageChannel,n=Array(1E3),A;A="undefined"!==typeof process&&"[object process]"==={}.toString.call(process)?F():B?G():w?H():I();var v=new D,y=new D;k.prototype.o=function(a){return E(a)};k.prototype.p=function(){return Error("Array Methods must be provided an Array")};k.prototype.l=
function(){this.b=Array(this.length)};k.prototype.k=function(){for(var a=this.length,b=this.c,c=this.m,d=0;void 0===b.a&&d<a;d++)this.j(c[d],d)};k.prototype.j=function(a,b){var c=this.n;"object"===typeof a&&null!==a?a.constructor===c&&void 0!==a.a?(a.f=null,this.g(a.a,b,a.b)):this.q(c.resolve(a),b):(this.d--,this.b[b]=this.h(a))};k.prototype.g=function(a,b,c){var d=this.c;void 0===d.a&&(this.d--,this.i&&2===a?g(d,c):this.b[b]=this.h(c));0===this.d&&m(d,this.b)};k.prototype.h=function(a){return a};
k.prototype.q=function(a,b){var c=this;u(a,void 0,function(a){c.g(1,b,a)},function(a){c.g(2,b,a)})};var O=0;h.all=function(a,b){return(new k(this,a,!0,b)).c};h.race=function(a,b){function c(a){q(e,a)}function d(a){g(e,a)}var e=new this(p,b);if(!E(a))return (g(e,new TypeError("You must pass an array to race.")), e);for(var f=a.length,h=0;void 0===e.a&&h<f;h++)u(this.resolve(a[h]),void 0,c,d);return e};h.resolve=function(a,b){if(a&&"object"===typeof a&&a.constructor===this)return a;var c=new this(p,b);
q(c,a);return c};h.reject=function(a,b){var c=new this(p,b);g(c,a);return c};h.prototype={constructor:h,then:function(a,b){var c=this.a;if(1===c&&!a||2===c&&!b)return this;var d=new this.constructor(p),e=this.b;if(c){var f=arguments[c-1];r(function(){C(c,d,f,e)})}else u(this,d,a,b);return d},"catch":function(a){return this.then(null,a)}};var z={Promise:h,polyfill:function(){var a;a="undefined"!==typeof global?global:"undefined"!==typeof window&&window.document?window:self;"Promise"in a&&"resolve"in
a.Promise&&"reject"in a.Promise&&"all"in a.Promise&&"race"in a.Promise&&function(){var b;new a.Promise(function(a){b=a});return s(b)}()||(a.Promise=h)}};"function"===typeof define&&define.amd?define(function(){return z}):"undefined"!==typeof module&&module.exports?module.exports=z:"undefined"!==typeof this&&(this.ES6Promise=z);}).call(window);
if (window) {
window.ES6Promise.polyfill();
}
module.exports = require('es6-promise').Promise;

View File

@@ -1,4 +1,12 @@
var Promise = require('./promise');
var XHR = require('./xhr');
var utils = require('./utils');
var log = require('./log');
var createWindowClone = require('./clone');
var decode64 = utils.decode64;
function Proxy(src, proxyUrl, document) {
var supportsCORS = ('withCredentials' in new XMLHttpRequest());
if (!proxyUrl) {
return Promise.reject("No proxy configured");
}
@@ -11,10 +19,8 @@ function Proxy(src, proxyUrl, document) {
}
var proxyCount = 0;
var supportsCORS = ('withCredentials' in new XMLHttpRequest());
var supportsCORSImage = ('crossOrigin' in new Image());
function ProxyURL(src, proxyUrl, document) {
var supportsCORSImage = ('crossOrigin' in new Image());
var callback = createCallback(supportsCORSImage);
var url = createProxyUrl(proxyUrl, src, callback);
return (supportsCORSImage ? Promise.resolve(url) : jsonp(document, url, callback).then(function(response) {
@@ -49,3 +55,42 @@ function createCallback(useCORS) {
function createProxyUrl(proxyUrl, src, callback) {
return proxyUrl + "?url=" + encodeURIComponent(src) + (callback.length ? "&callback=html2canvas.proxy." + callback : "");
}
function documentFromHTML(src) {
return function(html) {
var parser = new DOMParser(), doc;
try {
doc = parser.parseFromString(html, "text/html");
} catch(e) {
log("DOMParser not supported, falling back to createHTMLDocument");
doc = document.implementation.createHTMLDocument("");
try {
doc.open();
doc.write(html);
doc.close();
} catch(ee) {
log("createHTMLDocument write not supported, falling back to document.body.innerHTML");
doc.body.innerHTML = html; // ie9 doesnt support writing to documentElement
}
}
var b = doc.querySelector("base");
if (!b || !b.href.host) {
var base = doc.createElement("base");
base.href = src;
doc.head.insertBefore(base, doc.head.firstChild);
}
return doc;
};
}
function loadUrlDocument(src, proxy, document, width, height, options) {
return new Proxy(src, proxy, window.document).then(documentFromHTML(src)).then(function(doc) {
return createWindowClone(doc, document, width, height, options, 0, 0);
});
}
exports.Proxy = Proxy;
exports.ProxyURL = ProxyURL;
exports.loadUrlDocument = loadUrlDocument;

View File

@@ -1,5 +1,7 @@
var ProxyURL = require('./proxy').ProxyURL;
var Promise = require('./promise');
function ProxyImageContainer(src, proxy) {
var script = document.createElement("script");
var link = document.createElement("a");
link.href = src;
src = link.href;
@@ -16,3 +18,5 @@ function ProxyImageContainer(src, proxy) {
})['catch'](reject);
});
}
module.exports = ProxyImageContainer;

View File

@@ -1,3 +1,5 @@
var NodeContainer = require('./nodecontainer');
function PseudoElementContainer(node, parent, type) {
NodeContainer.call(this, node, parent);
this.isPseudoElement = true;
@@ -32,3 +34,5 @@ PseudoElementContainer.prototype.getHideClass = function() {
PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE = "___html2canvas___pseudoelement_before";
PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER = "___html2canvas___pseudoelement_after";
module.exports = PseudoElementContainer;

Submodule src/punycode deleted from 5c04e6fe95

View File

@@ -1,3 +1,5 @@
var log = require('./log');
function Renderer(width, height, images, options, document) {
this.width = width;
this.height = height;
@@ -102,3 +104,5 @@ Renderer.prototype.renderBackgroundRepeating = function(container, bounds, image
break;
}
};
module.exports = Renderer;

View File

@@ -1,3 +1,7 @@
var Renderer = require('../renderer');
var LinearGradientContainer = require('../lineargradientcontainer');
var log = require('../log');
function CanvasRenderer(width, height) {
Renderer.apply(this, arguments);
this.canvas = this.options.canvas || this.document.createElement("canvas");
@@ -173,3 +177,5 @@ CanvasRenderer.prototype.resizeImage = function(imageContainer, size) {
function hasEntries(array) {
return array.length > 0;
}
module.exports = CanvasRenderer;

View File

@@ -1,3 +1,5 @@
var NodeContainer = require('./nodecontainer');
function StackingContext(hasOwnStacking, opacity, element, parent) {
NodeContainer.call(this, element, parent);
this.ownStacking = hasOwnStacking;
@@ -12,3 +14,5 @@ StackingContext.prototype.getParentStack = function(context) {
var parentStack = (this.parent) ? this.parent.stack : null;
return parentStack ? (parentStack.ownStacking ? parentStack : parentStack.getParentStack(context)) : context.stack;
};
module.exports = StackingContext;

View File

@@ -47,3 +47,5 @@ Support.prototype.testSVG = function() {
}
return true;
};
module.exports = Support;

View File

@@ -1,3 +1,7 @@
var Promise = require('./promise');
var XHR = require('./xhr');
var decode64 = require('./utils').decode64;
function SVGContainer(src) {
this.src = src;
this.image = null;
@@ -7,13 +11,13 @@ function SVGContainer(src) {
return (self.isInline(src) ? Promise.resolve(self.inlineFormatting(src)) : XHR(src));
}).then(function(svg) {
return new Promise(function(resolve) {
html2canvas.fabric.loadSVGFromString(svg, self.createCanvas.call(self, resolve));
window.html2canvas.svg.fabric.loadSVGFromString(svg, self.createCanvas.call(self, resolve));
});
});
}
SVGContainer.prototype.hasFabric = function() {
return !html2canvas.fabric ? Promise.reject(new Error("html2canvas.svg.js is not loaded, cannot render svg")) : Promise.resolve();
return !window.html2canvas.svg || !window.html2canvas.svg.fabric ? Promise.reject(new Error("html2canvas.svg.js is not loaded, cannot render svg")) : Promise.resolve();
};
SVGContainer.prototype.inlineFormatting = function(src) {
@@ -31,12 +35,12 @@ SVGContainer.prototype.isInline = function(src) {
SVGContainer.prototype.createCanvas = function(resolve) {
var self = this;
return function (objects, options) {
var canvas = new html2canvas.fabric.StaticCanvas('c');
var canvas = new window.html2canvas.svg.fabric.StaticCanvas('c');
self.image = canvas.lowerCanvasEl;
canvas
.setWidth(options.width)
.setHeight(options.height)
.add(html2canvas.fabric.util.groupSVGElements(objects, options))
.add(window.html2canvas.svg.fabric.util.groupSVGElements(objects, options))
.renderAll();
resolve(canvas.lowerCanvasEl);
};
@@ -46,37 +50,4 @@ SVGContainer.prototype.decode64 = function(str) {
return (typeof(window.atob) === "function") ? window.atob(str) : decode64(str);
};
/*
* base64-arraybuffer
* https://github.com/niklasvh/base64-arraybuffer
*
* Copyright (c) 2012 Niklas von Hertzen
* Licensed under the MIT license.
*/
function decode64(base64) {
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var len = base64.length, i, encoded1, encoded2, encoded3, encoded4, byte1, byte2, byte3;
var output = "";
for (i = 0; i < len; i+=4) {
encoded1 = chars.indexOf(base64[i]);
encoded2 = chars.indexOf(base64[i+1]);
encoded3 = chars.indexOf(base64[i+2]);
encoded4 = chars.indexOf(base64[i+3]);
byte1 = (encoded1 << 2) | (encoded2 >> 4);
byte2 = ((encoded2 & 15) << 4) | (encoded3 >> 2);
byte3 = ((encoded3 & 3) << 6) | encoded4;
if (encoded3 === 64) {
output += String.fromCharCode(byte1);
} else if (encoded4 === 64 || encoded4 === -1) {
output += String.fromCharCode(byte1, byte2);
} else{
output += String.fromCharCode(byte1, byte2, byte3);
}
}
return output;
}
module.exports = SVGContainer;

View File

@@ -1,9 +1,12 @@
function SVGNodeContainer(node, native) {
var SVGContainer = require('./svgcontainer');
var Promise = require('./promise');
function SVGNodeContainer(node, _native) {
this.src = node;
this.image = null;
var self = this;
this.promise = native ? new Promise(function(resolve, reject) {
this.promise = _native ? new Promise(function(resolve, reject) {
self.image = new Image();
self.image.onload = resolve;
self.image.onerror = reject;
@@ -13,9 +16,11 @@ function SVGNodeContainer(node, native) {
}
}) : this.hasFabric().then(function() {
return new Promise(function(resolve) {
html2canvas.fabric.parseSVGDocument(node, self.createCanvas.call(self, resolve));
window.html2canvas.svg.fabric.parseSVGDocument(node, self.createCanvas.call(self, resolve));
});
});
}
SVGNodeContainer.prototype = Object.create(SVGContainer.prototype);
module.exports = SVGNodeContainer;

View File

@@ -1,3 +1,5 @@
var NodeContainer = require('./nodecontainer');
function TextContainer(node, parent) {
NodeContainer.call(this, node, parent);
}
@@ -27,3 +29,5 @@ function capitalize(m, p1, p2) {
return p1 + p2.toUpperCase();
}
}
module.exports = TextContainer;

169
src/utils.js Normal file
View File

@@ -0,0 +1,169 @@
exports.smallImage = function smallImage() {
return "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
};
exports.bind = function(callback, context) {
return function() {
return callback.apply(context, arguments);
};
};
/*
* base64-arraybuffer
* https://github.com/niklasvh/base64-arraybuffer
*
* Copyright (c) 2012 Niklas von Hertzen
* Licensed under the MIT license.
*/
exports.decode64 = function(base64) {
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var len = base64.length, i, encoded1, encoded2, encoded3, encoded4, byte1, byte2, byte3;
var output = "";
for (i = 0; i < len; i+=4) {
encoded1 = chars.indexOf(base64[i]);
encoded2 = chars.indexOf(base64[i+1]);
encoded3 = chars.indexOf(base64[i+2]);
encoded4 = chars.indexOf(base64[i+3]);
byte1 = (encoded1 << 2) | (encoded2 >> 4);
byte2 = ((encoded2 & 15) << 4) | (encoded3 >> 2);
byte3 = ((encoded3 & 3) << 6) | encoded4;
if (encoded3 === 64) {
output += String.fromCharCode(byte1);
} else if (encoded4 === 64 || encoded4 === -1) {
output += String.fromCharCode(byte1, byte2);
} else{
output += String.fromCharCode(byte1, byte2, byte3);
}
}
return output;
};
exports.getBounds = function(node) {
if (node.getBoundingClientRect) {
var clientRect = node.getBoundingClientRect();
var width = node.offsetWidth == null ? clientRect.width : node.offsetWidth;
return {
top: clientRect.top,
bottom: clientRect.bottom || (clientRect.top + clientRect.height),
right: clientRect.left + width,
left: clientRect.left,
width: width,
height: node.offsetHeight == null ? clientRect.height : node.offsetHeight
};
}
return {};
};
exports.offsetBounds = function(node) {
var parent = node.offsetParent ? exports.offsetBounds(node.offsetParent) : {top: 0, left: 0};
return {
top: node.offsetTop + parent.top,
bottom: node.offsetTop + node.offsetHeight + parent.top,
right: node.offsetLeft + parent.left + node.offsetWidth,
left: node.offsetLeft + parent.left,
width: node.offsetWidth,
height: node.offsetHeight
};
};
exports.parseBackgrounds = function(backgroundImage) {
var whitespace = ' \r\n\t',
method, definition, prefix, prefix_i, block, results = [],
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,
image: null
});
}
args = [];
method = prefix = definition = block = '';
};
args = [];
method = prefix = definition = block = '';
backgroundImage.split("").forEach(function(c) {
if (mode === 0 && whitespace.indexOf(c) > -1) {
return;
}
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;
return;
} else {
numParen++;
}
break;
case ')':
if (quote) {
break;
} else if(mode === 1) {
if(numParen === 0) {
mode = 0;
block += c;
appendResult();
return;
} else {
numParen--;
}
}
break;
case ',':
if (quote) {
break;
} else if(mode === 0) {
appendResult();
return;
} else if (mode === 1) {
if (numParen === 0 && !method.match(/^url$/i)) {
args.push(definition);
definition = '';
block += c;
return;
}
}
break;
}
block += c;
if (mode === 0) {
method += c;
} else {
definition += c;
}
});
appendResult();
return results;
};

View File

@@ -1,6 +1,10 @@
var GradientContainer = require('./gradientcontainer');
function WebkitGradientContainer(imageData) {
GradientContainer.apply(this, arguments);
this.type = (imageData.args[0] === "linear") ? this.TYPES.LINEAR : this.TYPES.RADIAL;
}
WebkitGradientContainer.prototype = Object.create(GradientContainer.prototype);
module.exports = WebkitGradientContainer;

View File

@@ -1,3 +1,5 @@
var Promise = require('./promise');
function XHR(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
@@ -18,3 +20,5 @@ function XHR(url) {
xhr.send();
});
}
module.exports = XHR;

141
tests/cases/acid2.html Normal file
View File

@@ -0,0 +1,141 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>The Second Acid Test</title>
<style type="text/css">
/* section numbers refer to CSS2.1 */
/* page setup */
html { font: 12px sans-serif; margin: 0; padding: 0; overflow: hidden; /* hides scrollbars on viewport, see 11.1.1:3 */ background: white; color: red; }
body { margin: 0; padding: 0; }
/* introduction message */
.intro { font: 2em sans-serif; margin: 3.5em 2em; padding: 0.5em; border: solid thin; background: white; color: black; position: relative; z-index: 2; /* should cover the black and red bars that are fixed-positioned */ }
.intro * { font: inherit; margin: 0; padding: 0; }
.intro h1 { font-size: 1em; font-weight: bolder; margin: 0; padding: 0; }
.intro :link { color: blue; }
.intro :visited { color: purple; }
/* picture setup */
#top { margin: 100em 3em 0; padding: 2em 0 0 .5em; text-align: left; font: 2em/24px sans-serif; color: navy; white-space: pre; } /* "Hello World!" text */
.picture { position: relative; border: 1em solid transparent; margin: 0 0 100em 3em; } /* containing block for face */
.picture { background: red; } /* overriden by preferred stylesheet below */
/* top line of face (scalp): fixed positioning and min/max height/width */
.picture p { position: fixed; margin: 0; padding: 0; border: 0; top: 9em; left: 11em; width: 140%; max-width: 4em; height: 8px; min-height: 1em; max-height: 2mm; /* min-height overrides max-height, see 10.7 */ background: black; border-bottom: 0.5em yellow solid; }
/* bits that shouldn't be part of the top line (and shouldn't be visible at all): HTML parsing, "+" combinator, stacking order */
.picture p.bad { border-bottom: red solid; /* shouldn't matter, because the "p + table + p" rule below should match it too, thus hiding it */ }
.picture p + p { background: maroon; z-index: 1; } /* shouldn't match anything */
.picture p + table + p { margin-top: 3em; /* should end up under the absolutely positioned table below, and thus not be visible */ }
/* second line of face: attribute selectors, float positioning */
[class~=one].first.one { position: absolute; top: 0; margin: 36px 0 0 60px; padding: 0; border: black 2em; border-style: none solid; /* shrink wraps around float */ }
[class~=one][class~=first] [class=second\ two][class="second two"] { float: right; width: 48px; height: 12px; background: yellow; margin: 0; padding: 0; } /* only content of abs pos block */
/* third line of face: width and overflow */
.forehead { margin: 4em; width: 8em; border-left: solid black 1em; border-right: solid black 1em; background: red url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR42mP4%2F58BAAT%2FAf9jgNErAAAAAElFTkSuQmCC); /* that's a 1x1 yellow pixel PNG */ }
.forehead * { width: 12em; line-height: 1em; }
/* class selectors headache */
.two.error.two { background: maroon; } /* shouldn't match */
.forehead.error.forehead { background: red; } /* shouldn't match */
[class=second two] { background: red; } /* this should be ignored (invalid selector -- grammar says it only accepts IDENTs or STRINGs) */
/* fourth and fifth lines of face, with eyes: paint order test (see appendix E) and fixed backgrounds */
/* the two images are identical: 2-by-2 squares with the top left
and bottom right pixels set to yellow and the other two set to
transparent. Since they are offset by one pixel from each other,
the second one paints exactly over the transparent parts of the
first one, thus creating a solid yellow block. */
.eyes { position: absolute; top: 5em; left: 3em; margin: 0; padding: 0; background: red; }
#eyes-a { height: 0; line-height: 2em; text-align: right; } /* contents should paint top-most because they're inline */
#eyes-a object { display: inline; vertical-align: bottom; }
#eyes-a object[type] { width: 7.5em; height: 2.5em; } /* should have no effect since that object should fallback to being inline (height/width don't apply to inlines) */
#eyes-a object object object { border-right: solid 1em black; padding: 0 12px 0 11px; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAABnRSTlMAAAAAAABupgeRAAAABmJLR0QA%2FwD%2FAP%2BgvaeTAAAAEUlEQVR42mP4%2F58BCv7%2FZwAAHfAD%2FabwPj4AAAAASUVORK5CYII%3D) fixed 1px 0; }
#eyes-b { float: left; width: 10em; height: 2em; background: fixed url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAABnRSTlMAAAAAAABupgeRAAAABmJLR0QA%2FwD%2FAP%2BgvaeTAAAAEUlEQVR42mP4%2F58BCv7%2FZwAAHfAD%2FabwPj4AAAAASUVORK5CYII%3D); border-left: solid 1em black; border-right: solid 1em red; } /* should paint in the middle layer because it is a float */
#eyes-c { display: block; background: red; border-left: 2em solid yellow; width: 10em; height: 2em; } /* should paint bottom most because it is a block */
/* lines six to nine, with nose: auto margins */
.nose { float: left; margin: -2em 2em -1em; border: solid 1em black; border-top: 0; min-height: 80%; height: 60%; max-height: 3em; /* percentages become auto (see 10.5 and 10.7) and intrinsic height is more than 3em, so 3em wins */ padding: 0; width: 12em; }
.nose > div { padding: 1em 1em 3em; height: 0; background: yellow; }
.nose div div { width: 2em; height: 2em; background: red; margin: auto; }
.nose :hover div { border-color: blue; }
.nose div:hover :before { border-bottom-color: inherit; }
.nose div:hover :after { border-top-color: inherit; }
.nose div div:before { display: block; border-style: none solid solid; border-color: red yellow black yellow; border-width: 1em; content: ''; height: 0; }
.nose div :after { display: block; border-style: solid solid none; border-color: black yellow red yellow; border-width: 1em; content: ''; height: 0; }
/* between lines nine and ten: margin collapsing with 'float' and 'clear' */
.empty { margin: 6.25em; height: 10%; /* computes to auto which makes it empty per 8.3.1:7 (own margins) */ }
.empty div { margin: 0 2em -6em 4em; }
.smile { margin: 5em 3em; clear: both; /* clearance is negative (see 8.3.1 and 9.5.1) */ }
/* line ten and eleven: containing block for abs pos */
.smile div { margin-top: 0.25em; background: black; width: 12em; height: 2em; position: relative; bottom: -1em; }
.smile div div { position: absolute; top: 0; right: 1em; width: auto; height: 0; margin: 0; border: yellow solid 1em; }
/* smile (over lines ten and eleven): backgrounds behind borders, inheritance of 'float', nested floats, negative heights */
.smile div div span { display: inline; margin: -1em 0 0 0; border: solid 1em transparent; border-style: none solid; float: right; background: black; height: 1em; }
.smile div div span em { float: inherit; border-top: solid yellow 1em; border-bottom: solid black 1em; } /* zero-height block; width comes from (zero-height) child. */
.smile div div span em strong { width: 6em; display: block; margin-bottom: -1em; /* should have no effect, since parent has top&bottom borders, so this margin doesn't collapse */ }
/* line twelve: line-height */
.chin { margin: -4em 4em 0; width: 8em; line-height: 1em; border-left: solid 1em black; border-right: solid 1em black; background: yellow url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAFSDNYfAAAAaklEQVR42u3XQQrAIAwAQeP%2F%2F6wf8CJBJTK9lnQ7FpHGaOurt1I34nfH9pMMZAZ8BwMGEvvh%2BBsJCAgICLwIOA8EBAQEBAQEBAQEBK79H5RfIQAAAAAAAAAAAAAAAAAAAAAAAAAAAID%2FABMSqAfj%2FsLmvAAAAABJRU5ErkJggg%3D%3D) /* 64x64 red square */ no-repeat fixed /* shouldn't be visible unless the smiley is moved to the top left of the viewport */; }
.chin div { display: inline; font: 2px/4px serif; }
/* line thirteen: cascade and selector tests */
.parser-container div { color: maroon; border: solid; color: orange; } /* setup */
div.parser-container * { border-color: black; /* overrides (implied) border-color on previous line */ } /* setup */
* div.parser { border-width: 0 2em; /* overrides (implied) declarations on earlier line */ } /* setup */
/* line thirteen continued: parser tests */
.parser { /* comment parsing test -- comment ends before the end of this line, the backslash should have no effect: \*/ }
.parser { margin: 0 5em 1em; padding: 0 1em; width: 2em; height: 1em; error: \}; background: yellow; } /* setup with parsing test */
* html .parser { background: gray; }
\.parser { padding: 2em; }
.parser { m\argin: 2em; };
.parser { height: 3em; }
.parser { width: 200; }
.parser { border: 5em solid red ! error; }
.parser { background: red pink; }
/* line fourteen (last line of face): table */
ul { display: table; padding: 0; margin: -1em 7em 0; background: red; }
ul li { padding: 0; margin: 0; }
ul li.first-part { display: table-cell; height: 1em; width: 1em; background: black; }
ul li.second-part { display: table; height: 1em; width: 1em; background: black; } /* anonymous table cell wraps around this */
ul li.third-part { display: table-cell; height: 0.5em; /* gets stretched to fit row */ width: 1em; background: black; }
ul li.fourth-part { list-style: none; height: 1em; width: 1em; background: black; } /* anonymous table cell wraps around this */
/* bits that shouldn't appear: inline alignment in cells */
.image-height-test { height: 10px; overflow: hidden; font: 20em serif; } /* only the area between the top of the line box and the top of the image should be visible */
table { margin: 0; border-spacing: 0; }
td { padding: 0; }
</style>
<link rel="appendix stylesheet" href="data:text/css,.picture%20%7B%20background%3A%20none%3B%20%7D"> <!-- this stylesheet should be applied by default -->
<script type="text/javascript" src="../test.js"></script>
</head>
<body>
<div style="margin: 70px;"></div>
<div class="picture">
<p><table><tr><td></table><p class="bad"> <!-- <table> closes <p> per the HTML4 DTD -->
<blockquote class="first one"><address class="second two"></address></blockquote>
<div class="forehead"><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div></div>
<div class="eyes"><div id="eyes-a"><object data="data:application/x-unknown,ERROR"><object data="http://www.damowmow.com/404/" type="text/html"><object data="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAYCAYAAAFy7sgCAAAGsUlEQVRo3u2ZbWwcZxHHf3s%2B7LNbO3ZjXBtowprGODRX0qpNQCjmJKuVKhMl1P2AkCwhFOIKkCBSm9IXavGFKAixIAECwkmWo5MrhRI3Ub40IEwQgp6aIDg3Cd6eEqyIHEteah%2B1E69vhw%2BZtTaX8704ZzkKjHS6271nZ56ZZ%2BY%2F%2F%2BdZKF%2FCwYshx3EkkggLsD1v4FQkEZZYLCbAKyG9%2Ba9EIsG6hnUAf8x74K3aUC3j4%2BM54HcsR2oAIomwZOezkv%2FnSHpYNh%2BNCmAE7xv94zvFdd1bHsjMZmQkPSxAJP%2B%2FfuBLwK54PC7JZFKAVJmzXLBt2w%2FMvcDLwIb8QS8CeJ4nkURYIomw7J%2FYJ8BvSiiXptGGxWds2%2Fa9%2Bnaxh%2BYAD%2Bgt04NDgABTpQY2cvvSFLzw86gWeBVwC8SzlOSv2YeBPfmDBoBHgKmR9LBEEmHZfDTqGykqfkUE0nA78BzQGfSgUeP3wNeTXwXg7MwZDhw4UHL6ra2ti79%2FOvljgG8AZ4H64Lhm4MvAocxsRppGG%2FxcXihlwLIs6R%2FfKV2HO%2F26uA94pdDYUKUZUU7W1RQYXA98Gnhaf5%2FXWX0HeAHYoQonqa4sZSOsSWMCWeC9Yko%2BCQwBe4E6oNc0Tc91XTl1%2BaTsn9gnI%2Blhyc5nZWxsrBIkKSbl2tiic3tW53YDEwOKaoFBrcOfqKee53lG9xsPMjV784r%2F4lO%2FpPvyJ9iyZcuvFSaXK5XYeAZ4CDgGvB3MS4B54LQuWYPeuy4iRFsevsXqpuYoqVQKIH2bK1CuDQNo11o4XUzh%2FcDWYIe1LEtyuZx4niee54njOGKapgfsqlL%2Bl2OjEXg8nxrc1dJ0h3hbtL%2BGCtz7KPBF4CuBe9uB15VafE8hr9qylI3HgG8C2%2FK7VyHZoJj7MrBRm30qFotJMpkU27YlHo%2F7Ha5a%2BV%2FKRkSJ4KuKRLVLKapTjB1SzAVIjY2NSXY%2BKyPpYdk%2FsU9OXT4pruv6BdZbBQfKsVGnvWlIe1VB6VQO8JxC1vZYLCbZ%2BaxsPhpdZDyRRFhG0sPiOE6ldKBg2lRg4xF1YCDIIIKN7DGgD3gH%2BBXwejKZfPrs2tPs%2FvPN2bKuYR1nd7xLKBSSJeqoXKnERjPwNWAG%2BLn2rZuM%2B4Tpml6vaWlp4eLcxVusZq5lCgVgOVKJjRqdX86ffL4D5wIoZACnTpw4wRMdT96i%2FImOJxERAs4uVyqxUacF%2FPdiCj%2BjdRBRGFtwXVdG0sPSdbhTmkYbpH98p2RmM2JZlig1vl0GWo4NQ%2Fn%2Bs5pKRXfwjweaxy7TND3HcRZbfC6X8xVPVQlGy7WxVWlO5XRXFXm6EZmrQuSXYyPE3SiVoEhE6Wyr0u2rumO6zv%2B21AFdQAswC1wCMuUCXCmyWQus103Qg8qlDO0lxwOb%2Fl4FiK3AB3VS%2FuKKLtK%2FgbeAnwG%2FvUODuRw%2FFrR0H1UC75fwu8oJ%2FhFsW5VIG%2FBUgEIN6Y65O4AHu4Ap0zQ9y7LEcZyb9lRBUHQcRyzL8unZVBW5bFWAvAp%2BhDQ2g4F47dUYtlU6obXA54DnVdFLekjUGGifh4AFy7LEdV3xj3X9I66m0QZpGm2QrsOd0j%2B%2BU0bSw5KZzYjrun6HWlAd961i4FfCj0aN1Usau%2Bc1lmuXPFwvAEumUut7tQQvAb%2FXb%2FT0bCAej9cODg7yt%2Bm%2F8q2%2F7OUHZ76PnZ1k2p0mJzlykmPancbOTnL0whHs7CQfb%2B5mx2d3sH79%2BtCRI0c6FeaOr9ICrIQfLvA%2B8BGNXxi4R6HrisJVUWrxAVW2oMFf0Aczim8o3kV6enowDIPjF9%2Fk%2BMU3S3rrjzMMg56eHr%2BxP7qKFbASfojG6kpeDGs1tiW53RxwWT%2Bin5q8w4xpQK5evQpAR30H7ZH2khNvj7TTUd8BgD4rqmu1ZKX8qNeY%2BfHz4zlXDgT5E8tpCTUq7XSBC4Euv8227TV9fX1E73%2BYtvo27BmbS9cvFVTY3bSRFza9yOcf6Gfmygy7d%2B%2Fm%2FPnzF4DvrsBLhnJlJfwIKXxv1PheAE4qK6p4H9AGbNKTuhngBPBPXYRe4IemaT5kWZbR19fHNbmGnZ1k4r3U4glDR30Hm5qjbGjsImJEOHbsGHv27JFz5869o0eFq01Jq%2BmHAXwI6FFKagMTgHM7GzFDS%2BoeLSMv7zjzC9x4Y7gxFovVDAwMEI1GaWlpWSzRVCrFwYMH%2FXfxZ4AfAa8B%2F7lDaGg1%2FQgp43lfK0yqtRMuJa3ceKe5DfgYsCYAZ2ngD8CfAkzqTpW7xY%2F%2FSznyX%2FVeUb2kVmX4AAAAAElFTkSuQmCC">ERROR</object></object></object></div><div id="eyes-b"></div><div id="eyes-c"></div></div> <!-- that's a PNG with 8bit alpha containing two eyes -->
<div class="nose"><div><div></div></div></div>
<div class="empty"><div></div></div>
<div class="smile"><div><div><span><em><strong></strong></em></span></div></div></div>
<div class="chin"><div>&nbsp;</div></div>
<div class="parser-container"><div class="parser"><!-- ->ERROR<!- --></div></div> <!-- two dashes is what delimits a comment, so the text "->ERROR<!-" earlier on this line is actually part of a comment -->
<ul>
<li class="first-part"></li>
<li class="second-part"></li>
<li class="third-part"></li>
<li class="fourth-part"></li>
</ul>
<div class="image-height-test"><table><tr><td><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAFSDNYfAAAAaklEQVR42u3XQQrAIAwAQeP%2F%2F6wf8CJBJTK9lnQ7FpHGaOurt1I34nfH9pMMZAZ8BwMGEvvh%2BBsJCAgICLwIOA8EBAQEBAQEBAQEBK79H5RfIQAAAAAAAAAAAAAAAAAAAAAAAAAAAID%2FABMSqAfj%2FsLmvAAAAABJRU5ErkJggg%3D%3D" alt=""></td></tr></table></div>
</div>
</body>
</html>

View File

@@ -112,6 +112,10 @@
.linearGradient8 {
background: linear-gradient(to top left, #fff 0%, #00263c 100%);
}
.linearGradient9 {
background: linear-gradient(to top left, white 0%, black 100%);
}
</style>
</head>
@@ -125,6 +129,7 @@
<div class="linearGradient6">&nbsp;</div>
<div class="linearGradient7">&nbsp;</div>
<div class="linearGradient8">&nbsp;</div>
<div class="linearGradient9">&nbsp;</div>
</div>
</body>
</html>

View File

@@ -29,7 +29,7 @@
.container {
float: left;
border: 1px solid black;
width: 200px;
width: 150px;
height: 200px;
background-image: url(../../assets/image.jpg);
background-size: 34px;
@@ -42,7 +42,7 @@
<div class="container"></div>
<div class="container" style="background-repeat: repeat-y"></div>
<div class="container" style="background-repeat: repeat-x"></div>
<div class="container" style="background-size: 150% auto"></div>
<div class="horizontal">
<div style='background-size: cover;'></div>
<div style='background-size: contain;'></div>

View File

@@ -57,6 +57,12 @@
background-clip: padding-box;
}
.box6 {
height: 200px;
width: 200px;
border-radius: 200px;
}
html {
background: #3a84c3;
}
@@ -69,5 +75,6 @@
<div class="box3">&nbsp;</div>
<div class="box4">&nbsp;</div>
<div class="box5">&nbsp;</div>
<div class="box6">&nbsp;</div>
</body>
</html>

View File

@@ -1,144 +0,0 @@
<html>
<head>
<meta charset="utf-8">
<title>Mocha Tests</title>
<link rel="stylesheet" href="lib/mocha.css" />
<script type="text/javascript" src="../../src/color.js"></script>
<script src="lib/expect.js"></script>
<script src="lib/mocha.js"></script>
</head>
<body>
<div id="mocha"></div>
<script>mocha.setup('bdd')</script>
<script>
describe("Colors", function() {
describe("named colors", function() {
it("bisque", function () {
var c = new Color("bisque");
assertColor(c, 255, 228, 196, null);
expect(c.isTransparent()).to.equal(false);
});
it("BLUE", function () {
var c = new Color("BLUE");
assertColor(c, 0, 0, 255, null);
expect(c.isTransparent()).to.equal(false);
});
});
describe("rgb()", function() {
it("rgb(1,3,5)", function () {
var c = new Color("rgb(1,3,5)");
assertColor(c, 1, 3, 5, null);
expect(c.isTransparent()).to.equal(false);
});
it("rgb(222, 111, 50)", function () {
var c = new Color("rgb(222, 111, 50)");
assertColor(c, 222, 111, 50, null);
expect(c.isTransparent()).to.equal(false);
});
it("rgb( 222, 111 , 50)", function () {
var c = new Color("rgb(222 , 111 , 50)");
assertColor(c, 222, 111, 50, null);
expect(c.isTransparent()).to.equal(false);
});
});
describe("rgba()", function() {
it("rgba(200,3,5,1)", function () {
var c = new Color("rgba(200,3,5,1)");
assertColor(c, 200, 3, 5, 1);
expect(c.isTransparent()).to.equal(false);
});
it("rgba(222, 111, 50, 0.22)", function () {
var c = new Color("rgba(222, 111, 50, 0.22)");
assertColor(c, 222, 111, 50, 0.22);
expect(c.isTransparent()).to.equal(false);
});
it("rgba( 222, 111 , 50, 0.123 )", function () {
var c = new Color("rgba(222 , 111 , 50, 0.123)");
assertColor(c, 222, 111, 50, 0.123);
expect(c.isTransparent()).to.equal(false);
});
});
describe("hex", function() {
it("#7FFFD4", function () {
var c = new Color("#7FFFD4");
assertColor(c, 127, 255, 212, null);
expect(c.isTransparent()).to.equal(false);
});
it("#f0ffff", function () {
var c = new Color("#f0ffff");
assertColor(c, 240, 255, 255, null);
expect(c.isTransparent()).to.equal(false);
});
it("#fff", function () {
var c = new Color("#fff");
assertColor(c, 255, 255, 255, null);
expect(c.isTransparent()).to.equal(false);
});
});
describe("from array", function() {
it("[1,2,3]", function () {
var c = new Color([1,2,3]);
assertColor(c, 1, 2, 3, null);
expect(c.isTransparent()).to.equal(false);
});
it("[5,6,7,1]", function () {
var c = new Color([5,6,7, 1]);
assertColor(c, 5, 6, 7, 1);
expect(c.isTransparent()).to.equal(false);
});
it("[5,6,7,0]", function () {
var c = new Color([5,6,7, 0]);
assertColor(c, 5, 6, 7, 0);
expect(c.isTransparent()).to.equal(true);
});
});
describe("transparency", function() {
it("transparent", function () {
var c = new Color("transparent");
assertColor(c, 0, 0, 0, 0);
expect(c.isTransparent()).to.equal(true);
});
it("rgba(255,255,255,0)", function () {
var c = new Color("rgba(255,255,255,0)");
assertColor(c, 255, 255, 255, 0);
expect(c.isTransparent()).to.equal(true);
});
});
});
function assertColor(c, r, g, b, a) {
expect(c.r).to.equal(r);
expect(c.g).to.equal(g);
expect(c.b).to.equal(b);
expect(c.a).to.equal(a);
}
mocha.checkLeaks();
mocha.globals(['jQuery']);
if (window.mochaPhantomJS) {
mochaPhantomJS.run();
}
else {
mocha.run();
}
mocha.suite.afterAll(function() {
document.body.setAttribute('data-complete', 'true');
});
</script>
</body>
</html>

View File

@@ -1,3 +1,5 @@
var NodeContainer = html2canvas.NodeContainer;
describe('Borders', function() {
$('#borders div').each(function(i, node) {
it($(this).attr('style'), function() {
@@ -41,7 +43,7 @@ describe('Background-position', function() {
var container = new NodeContainer(node, null);
var item = container.css(prop),
backgroundPosition = container.parseBackgroundPosition(getBounds(node), img),
backgroundPosition = container.parseBackgroundPosition(html2canvas.utils.getBounds(node), img),
split = (window.getComputedStyle) ? $(node).css(prop).split(" ") : [$(node).css(prop+"X"), $(node).css(prop+"Y")];
var testEl = $('<div />').css({
@@ -65,26 +67,28 @@ describe('Text-shadow', function() {
var index = i + 1;
var container = new NodeContainer(node, null);
var shadows = container.parseTextShadows();
if (i === 0) {
expect(shadows.length).to.equal(0);
} else {
expect(shadows.length).to.equal(i >= 6 ? 2 : 1);
expect(shadows[0].offsetX).to.equal(i);
expect(shadows[0].offsetY).to.equal(i);
if (i < 2) {
expect(shadows[0].color.toString()).to.equal('rgba(0,0,0,0)');
} else if (i % 2 === 0) {
expect(shadows[0].color.toString()).to.equal('rgb(2,2,2)');
it(node.style.textShadow, function() {
if (i === 0) {
expect(shadows.length).to.equal(0);
} else {
var opacity = '0.2';
expect(shadows[0].color.toString()).to.match(/rgba\(2,2,2,(0.2|0\.199219)\)/);
}
expect(shadows.length).to.equal(i >= 6 ? 2 : 1);
expect(shadows[0].offsetX).to.equal(i);
expect(shadows[0].offsetY).to.equal(i);
if (i < 2) {
expect(shadows[0].color.toString()).to.equal('rgba(0,0,0,0)');
} else if (i % 2 === 0) {
expect(shadows[0].color.toString()).to.equal('rgb(2,2,2)');
} else {
var opacity = '0.2';
expect(shadows[0].color.toString()).to.match(/rgba\(2,2,2,(0.2|0\.199219)\)/);
}
// only testing blur once
if (i === 1) {
expect(shadows[0].blur).to.equal('1');
// only testing blur once
if (i === 1) {
expect(shadows[0].blur).to.equal('1');
}
}
}
});
});
});
@@ -210,7 +214,7 @@ describe('Background-image', function() {
function test_parse_background_image(value, expected, name) {
it(name, function() {
expect(parseBackgrounds(value)).to.eql(Array.isArray(expected) ? expected : [expected]);
expect(html2canvas.utils.parseBackgrounds(value)).to.eql(Array.isArray(expected) ? expected : [expected]);
});
}
});

View File

@@ -4,9 +4,6 @@
<title>Mocha Tests</title>
<link rel="stylesheet" href="lib/mocha.css" />
<script src="../../dist/html2canvas.js"></script>
<script src="../../src/log.js"></script>
<script src="../../src/renderer.js"></script>
<script src="../../src/renderers/canvas.js"></script>
<script src="../assets/jquery-1.6.2.js"></script>
<script src="lib/expect.js"></script>
<script src="lib/mocha.js"></script>
@@ -44,6 +41,8 @@
<div id="green-block"></div>
<script>
var CanvasRenderer = html2canvas.CanvasRenderer;
describe("Rendering input values", function() {
it("uses default value for input[type='text']", function(done) {
CanvasRenderer.prototype.text = function(text) {
@@ -109,7 +108,7 @@
CanvasRenderer.prototype.text = function(text) {
expect(text).to.equal('updated');
};
html2canvas(document.querySelector("#block4"), {renderer: CanvasRenderer, strict: true, logging: true, removeContainer: false}).then(function(canvas) {
html2canvas(document.querySelector("#block4"), {renderer: CanvasRenderer, strict: true}).then(function(canvas) {
expect(canvas.width).to.equal(200);
expect(canvas.height).to.equal(200);
done();
@@ -139,7 +138,7 @@
CanvasRenderer.prototype.text = function(text) {
expect(text).to.equal('3');
};
html2canvas(document.querySelector("#block5"), {renderer: CanvasRenderer, strict: true, logging: true, removeContainer: false}).then(function(canvas) {
html2canvas(document.querySelector("#block5"), {renderer: CanvasRenderer, strict: true}).then(function(canvas) {
expect(canvas.width).to.equal(200);
expect(canvas.height).to.equal(200);
done();

View File

@@ -35,6 +35,15 @@ describe("Gradients", function() {
" to(rgb(191, 110, 78))"
]
},
{
method: 'linear-gradient',
args: [
"0deg",
" rgb(221, 221, 221)",
" rgb(221, 221, 221) 50%",
" transparent 50%"
]
},
{
method: "radial-gradient",
args: [
@@ -97,11 +106,11 @@ describe("Gradients", function() {
}
];
$('#backgroundGradients div').each(function(i, node) {
var container = new NodeContainer(node, null);
[].slice.call(document.querySelectorAll('#backgroundGradients div'), 0).forEach(function(node, i) {
var container = new html2canvas.NodeContainer(node, null);
var value = container.css("backgroundImage");
it(value, function() {
var parsedBackground = parseBackgrounds(value);
var parsedBackground = html2canvas.utils.parseBackgrounds(value);
if (parsedBackground[0].args[0] === "0% 50%") {
parsedBackground[0].args[0] = 'left';
}

View File

@@ -25,6 +25,7 @@
<div id="green-block"></div>
<script>mocha.setup('bdd')</script>
<script>
var Promise = html2canvas.Promise;
describe("Multiple renders", function() {
it("render correctly", function(done) {
this.timeout(10000);

View File

@@ -23,6 +23,7 @@
<div style="background: red; width: 200px; height:200px;" id="block"></div>
<div style="width: 200px; height:200px;" id="block2"></div>
<script>
var Promise = html2canvas.Promise;
describe("options.onclone", function() {
it("with a function", function(done) {
html2canvas(document.querySelector("#block"), {onclone: function(document) {

View File

@@ -3,23 +3,7 @@
<meta charset="utf-8">
<title>Mocha Tests</title>
<link rel="stylesheet" href="lib/mocha.css" />
<script type="text/javascript" src="../../src/log.js"></script>
<script type="text/javascript" src="../../src/color.js"></script>
<script type="text/javascript" src="../../src/nodecontainer.js"></script>
<script type="text/javascript" src="../../src/stackingcontext.js"></script>
<script type="text/javascript" src="../../src/textcontainer.js"></script>
<script type="text/javascript" src="../../src/support.js"></script>
<script type="text/javascript" src="../../src/imagecontainer.js"></script>
<script type="text/javascript" src="../../src/gradientcontainer.js"></script>
<script type="text/javascript" src="../../src/lineargradientcontainer.js"></script>
<script type="text/javascript" src="../../src/webkitgradientcontainer.js"></script>
<script type="text/javascript" src="../../src/imageloader.js"></script>
<script type="text/javascript" src="../../src/nodeparser.js"></script>
<script type="text/javascript" src="../../src/font.js"></script>
<script type="text/javascript" src="../../src/fontmetrics.js"></script>
<script type="text/javascript" src="../../src/renderer.js"></script>
<script type="text/javascript" src="../../src/promise.js"></script>
<script type="text/javascript" src="../../src/renderers/canvas.js"></script>
<script src="../../dist/html2canvas.js"></script>
<script src="../assets/jquery-1.6.2.js"></script>
<script src="lib/expect.js"></script>
<script src="lib/mocha.js"></script>
@@ -124,6 +108,12 @@
/* W3C */
background: linear-gradient(top, #f0b7a1 0%, #8c3310 50%, #752201 51%, #bf6e4e 100%);
}
.linearGradient4 {
background: -webkit-linear-gradient(0deg, #ddd, #ddd 50%, transparent 50%);
background: linear-gradient(0deg, #ddd, #ddd 50%, transparent 50%);
}
.radialGradient {
background: -moz-radial-gradient(75% 19%, ellipse closest-side, #ababab, #0000ff 33%,#991f1f 100%);
background: -webkit-radial-gradient(75% 19%, ellipse closest-side, #ababab, #0000ff 33%,#991f1f 100%);
@@ -172,6 +162,7 @@
<div class="linearGradientSimple"></div>
<div class="linearGradientWithStops"></div>
<div class="linearGradient3"></div>
<div class="linearGradient4"></div>
<div class="radialGradient"></div>
<div class="radialGradient2"></div>
<div class="radialGradient3"></div>

View File

@@ -12,6 +12,12 @@
<body>
<div id="mocha"></div>
<script>mocha.setup('bdd')</script>
<div id="scroll-render" style="height: 200px; width: 200px;">
<div style="height: 500px; width: 400px;overflow: scroll;" id="scrollable">
<div style="height: 500px;background: red;"></div>
<div style="height: 650px; background: green"></div>
</div>
</div>
<div style="height: 2200px;"></div>
<div style="height: 500px;background: green;"><a name="content">content</a></div>
<script>
@@ -32,7 +38,7 @@
window.location.hash = "#content";
setTimeout(function() {
var top = $(window).scrollTop();
html2canvas(document.body, {type: 'view', removeContainer: false}).then(function () {
html2canvas(document.body, {type: 'view'}).then(function () {
var currentTop = $(window).scrollTop();
window.location.hash = "";
expect(currentTop).to.be.greaterThan(1500);
@@ -45,8 +51,35 @@
});
}, 0);
});
it("with content scroll", function (done) {
$("#scrollable").scrollTop(500);
setTimeout(function() {
html2canvas(document.querySelector("#scroll-render")).then(function (canvas) {
expect($("#scrollable").scrollTop()).to.equal(500);
document.body.appendChild(canvas);
expect(canvas.width).to.equal(200);
expect(canvas.height).to.equal(200);
validCanvasPixels(canvas);
done();
}).catch(function (error) {
done(error);
});
}, 0);
});
});
function validCanvasPixels(canvas) {
var ctx = canvas.getContext("2d");
var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
for (var i = 0, len = 200*199*4; i < len; i+=4) {
if (data[i] !== 0 || data[i+1] !== 128 || data[i+2] !== 0 || data[i+3] !== 255) {
console.log(i, data[i], data[i+1], data[i+2], data[i+3]);
expect().fail("Invalid canvas data");
}
}
}
after(function() {
if (history) {
history.pushState("", document.title, window.location.pathname + window.location.search);

119
tests/node/color.js Normal file
View File

@@ -0,0 +1,119 @@
var Color = require('../../src/color');
var assert = require('assert');
describe("Colors", function() {
describe("named colors", function() {
it("bisque", function () {
var c = new Color("bisque");
assertColor(c, 255, 228, 196, null);
assert.equal(c.isTransparent(), false);
});
it("BLUE", function () {
var c = new Color("BLUE");
assertColor(c, 0, 0, 255, null);
assert.equal(c.isTransparent(), false);
});
});
describe("rgb()", function() {
it("rgb(1,3,5)", function () {
var c = new Color("rgb(1,3,5)");
assertColor(c, 1, 3, 5, null);
assert.equal(c.isTransparent(), false);
});
it("rgb(222, 111, 50)", function () {
var c = new Color("rgb(222, 111, 50)");
assertColor(c, 222, 111, 50, null);
assert.equal(c.isTransparent(), false);
});
it("rgb( 222, 111 , 50)", function () {
var c = new Color("rgb(222 , 111 , 50)");
assertColor(c, 222, 111, 50, null);
assert.equal(c.isTransparent(), false);
});
});
describe("rgba()", function() {
it("rgba(200,3,5,1)", function () {
var c = new Color("rgba(200,3,5,1)");
assertColor(c, 200, 3, 5, 1);
assert.equal(c.isTransparent(), false);
});
it("rgba(222, 111, 50, 0.22)", function () {
var c = new Color("rgba(222, 111, 50, 0.22)");
assertColor(c, 222, 111, 50, 0.22);
assert.equal(c.isTransparent(), false);
});
it("rgba( 222, 111 , 50, 0.123 )", function () {
var c = new Color("rgba(222 , 111 , 50, 0.123)");
assertColor(c, 222, 111, 50, 0.123);
assert.equal(c.isTransparent(), false);
});
});
describe("hex", function() {
it("#7FFFD4", function () {
var c = new Color("#7FFFD4");
assertColor(c, 127, 255, 212, null);
assert.equal(c.isTransparent(), false);
});
it("#f0ffff", function () {
var c = new Color("#f0ffff");
assertColor(c, 240, 255, 255, null);
assert.equal(c.isTransparent(), false);
});
it("#fff", function () {
var c = new Color("#fff");
assertColor(c, 255, 255, 255, null);
assert.equal(c.isTransparent(), false);
});
});
describe("from array", function() {
it("[1,2,3]", function () {
var c = new Color([1,2,3]);
assertColor(c, 1, 2, 3, null);
assert.equal(c.isTransparent(), false);
});
it("[5,6,7,1]", function () {
var c = new Color([5,6,7, 1]);
assertColor(c, 5, 6, 7, 1);
assert.equal(c.isTransparent(), false);
});
it("[5,6,7,0]", function () {
var c = new Color([5,6,7, 0]);
assertColor(c, 5, 6, 7, 0);
assert.equal(c.isTransparent(), true);
});
});
describe("transparency", function() {
it("transparent", function () {
var c = new Color("transparent");
assertColor(c, 0, 0, 0, 0);
assert.equal(c.isTransparent(), true);
});
it("rgba(255,255,255,0)", function () {
var c = new Color("rgba(255,255,255,0)");
assertColor(c, 255, 255, 255, 0);
assert.equal(c.isTransparent(), true);
});
});
});
function assertColor(c, r, g, b, a) {
assert.equal(c.r, r);
assert.equal(c.g, g);
assert.equal(c.b, b);
assert.equal(c.a, a);
}

View File

@@ -1,4 +1,5 @@
var assert = require('assert');
var path = require('path');
var html2canvas = require('../../');
describe("Package", function() {
@@ -6,3 +7,18 @@ describe("Package", function() {
assert.equal(typeof(html2canvas), "function");
});
});
describe.only("requirejs", function() {
var requirejs = require('requirejs');
requirejs.config({
baseUrl: path.resolve(__dirname, '../../dist')
});
it("should have html2canvas defined", function(done) {
requirejs(['html2canvas'], function(h2c) {
assert.equal(typeof(h2c), "function");
done();
});
});
});

View File

@@ -1,10 +1,3 @@
/*
html2canvas @VERSION@ <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Released under MIT License
*/
var h2cSelector, h2cOptions;
(function(document, window) {
function appendScript(src) {
@@ -14,7 +7,7 @@ var h2cSelector, h2cOptions;
var sources = ['log', 'punycode/punycode', 'core', 'nodecontainer', 'pseudoelementcontainer', 'stackingcontext', 'textcontainer', 'support', 'imagecontainer', 'dummyimagecontainer', 'proxyimagecontainer', 'gradientcontainer',
'lineargradientcontainer', 'webkitgradientcontainer', 'svgcontainer', 'svgnodecontainer', 'imageloader', 'nodeparser', 'font', 'fontmetrics', 'renderer', 'promise', 'xhr', 'framecontainer', 'proxy', 'color', 'renderers/canvas'];
['/tests/assets/jquery-1.6.2'].concat(window.location.search === "?selenium" ? ['/dist/html2canvas'] : sources.map(function(src) { return '/src/' + src; })).forEach(appendScript);
['/tests/assets/jquery-1.6.2', '/dist/html2canvas'].forEach(appendScript);
if (typeof(noFabric) === "undefined") {
appendScript('/dist/html2canvas.svg');
@@ -104,7 +97,7 @@ var h2cSelector, h2cOptions;
textDecoration:'none',
display:'none'
}).appendTo(document.body).fadeIn();
log(msg);
console.log(msg);
}
};
})(jQuery);