Skip to content

Commit

Permalink
Correctly render input[type="password"] value
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasvh committed Jan 5, 2015
1 parent e363f38 commit 4985279
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 18 deletions.
22 changes: 15 additions & 7 deletions dist/html2canvas.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
html2canvas 0.5.0-alpha <http://html2canvas.hertzen.com>
Copyright (c) 2014 Niklas von Hertzen
Copyright (c) 2015 Niklas von Hertzen
Released under MIT License
*/
Expand Down Expand Up @@ -580,6 +580,7 @@ window.html2canvas = function(nodeList, options) {
options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer;
options.javascriptEnabled = typeof(options.javascriptEnabled) === "undefined" ? false : options.javascriptEnabled;
options.imageTimeout = typeof(options.imageTimeout) === "undefined" ? 10000 : options.imageTimeout;
options.renderer = typeof(options.renderer) === "function" ? options.renderer : CanvasRenderer;

if (typeof(nodeList) === "string") {
if (typeof(options.proxy) !== "string") {
Expand Down Expand Up @@ -626,7 +627,7 @@ function renderWindow(node, container, options, windowWidth, windowHeight) {
var bounds = getBounds(node);
var width = options.type === "view" ? windowWidth : documentWidth(clonedWindow.document);
var height = options.type === "view" ? windowHeight : documentHeight(clonedWindow.document);
var renderer = new CanvasRenderer(width, height, imageLoader, options, document);
var renderer = new options.renderer(width, height, imageLoader, options, document);
var parser = new NodeParser(node, renderer, support, imageLoader, options);
return parser.ready.then(function() {
log("Finished rendering");
Expand Down Expand Up @@ -1691,7 +1692,11 @@ NodeContainer.prototype.hasTransform = function() {

NodeContainer.prototype.getValue = function() {
var value = this.node.value || "";
value = (this.node.tagName === "SELECT") ? selectionValue(this.node) : value;
if (this.node.tagName === "SELECT") {
value = selectionValue(this.node);
} else if (this.node.type === "password") {
value = Array(value.length + 1).join('\u2022'); // jshint ignore:line
}
return value.length === 0 ? (this.node.placeholder || "") : value;
};

Expand Down Expand Up @@ -1859,6 +1864,9 @@ function NodeParser(element, renderer, support, imageLoader, options) {
this.renderQueue = [];
this.stack = new StackingContext(true, 1, element.ownerDocument, null);
var parent = new NodeContainer(element, null);
if (options.background) {
renderer.rectangle(0, 0, renderer.width, renderer.height, new Color(options.background));
}
if (element === element.ownerDocument.documentElement) {
// http://www.w3.org/TR/css3-background/#special-backgrounds
var canvasBackground = new NodeContainer(parent.color('backgroundColor').isTransparent() ? element.ownerDocument.body : element.ownerDocument.documentElement, null);
Expand Down Expand Up @@ -2135,6 +2143,9 @@ NodeParser.prototype.paint = function(container) {
}
} catch(e) {
log(e);
if (this.options.strict) {
throw e;
}
}
};

Expand Down Expand Up @@ -3147,9 +3158,6 @@ function CanvasRenderer(width, height) {
this.canvas.height = height;
}
this.ctx = this.canvas.getContext("2d");
if (this.options.background) {
this.rectangle(0, 0, width, height, new Color(this.options.background));
}
this.taintCtx = this.document.createElement("canvas").getContext("2d");
this.ctx.textBaseline = "bottom";
this.variables = {};
Expand All @@ -3159,7 +3167,7 @@ function CanvasRenderer(width, height) {
CanvasRenderer.prototype = Object.create(Renderer.prototype);

CanvasRenderer.prototype.setFillStyle = function(fillStyle) {
this.ctx.fillStyle = (fillStyle instanceof Color) ? fillStyle.toString() : fillStyle;
this.ctx.fillStyle = typeof(fillStyle) === "object" ? fillStyle.toString() : fillStyle;

This comment has been minimized.

Copy link
@usmonster

usmonster Jan 6, 2015

Contributor

If fillStyle is a CanvasGradient, then typeof(fillStyle) === "object" is true, but fillStyle.toString() will be "[object CanvasGradient]", which is probably not wanted..

This comment has been minimized.

Copy link
@niklasvh

niklasvh Jan 7, 2015

Author Owner

Well spotted, will get that fixed.

This comment has been minimized.

Copy link
@calebj0seph

calebj0seph Jan 10, 2015

This line has broken rendering background images too. Reverting it fixes #496.

This comment has been minimized.

Copy link
@usmonster

usmonster Jan 10, 2015

Contributor

Instead of reverting, a workaround could be to change the test condition to typeof(fillStyle) === "object" && "rgb" in fillStyle. @niklasvh, what are the possible types that fillStyle can be? We may be able to just test for string or CanvasGradient.

This comment has been minimized.

Copy link
@niklasvh

niklasvh Jan 10, 2015

Author Owner

Added fix in 7a58ad0

return this.ctx;
};

Expand Down
6 changes: 3 additions & 3 deletions dist/html2canvas.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/html2canvas.svg.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
html2canvas 0.5.0-alpha <http://html2canvas.hertzen.com>
Copyright (c) 2014 Niklas von Hertzen
Copyright (c) 2015 Niklas von Hertzen

Released under MIT License
*/
Expand Down
2 changes: 1 addition & 1 deletion dist/html2canvas.svg.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ window.html2canvas = function(nodeList, options) {
options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer;
options.javascriptEnabled = typeof(options.javascriptEnabled) === "undefined" ? false : options.javascriptEnabled;
options.imageTimeout = typeof(options.imageTimeout) === "undefined" ? 10000 : options.imageTimeout;
options.renderer = typeof(options.renderer) === "function" ? options.renderer : CanvasRenderer;

if (typeof(nodeList) === "string") {
if (typeof(options.proxy) !== "string") {
Expand Down Expand Up @@ -62,7 +63,7 @@ function renderWindow(node, container, options, windowWidth, windowHeight) {
var bounds = getBounds(node);
var width = options.type === "view" ? windowWidth : documentWidth(clonedWindow.document);
var height = options.type === "view" ? windowHeight : documentHeight(clonedWindow.document);
var renderer = new CanvasRenderer(width, height, imageLoader, options, document);
var renderer = new options.renderer(width, height, imageLoader, options, document);
var parser = new NodeParser(node, renderer, support, imageLoader, options);
return parser.ready.then(function() {
log("Finished rendering");
Expand Down
6 changes: 5 additions & 1 deletion src/nodecontainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,11 @@ NodeContainer.prototype.hasTransform = function() {

NodeContainer.prototype.getValue = function() {
var value = this.node.value || "";
value = (this.node.tagName === "SELECT") ? selectionValue(this.node) : value;
if (this.node.tagName === "SELECT") {
value = selectionValue(this.node);
} else if (this.node.type === "password") {
value = Array(value.length + 1).join('\u2022'); // jshint ignore:line
}
return value.length === 0 ? (this.node.placeholder || "") : value;
};

Expand Down
6 changes: 6 additions & 0 deletions src/nodeparser.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ function NodeParser(element, renderer, support, imageLoader, options) {
this.renderQueue = [];
this.stack = new StackingContext(true, 1, element.ownerDocument, null);
var parent = new NodeContainer(element, null);
if (options.background) {
renderer.rectangle(0, 0, renderer.width, renderer.height, new Color(options.background));
}
if (element === element.ownerDocument.documentElement) {
// http://www.w3.org/TR/css3-background/#special-backgrounds
var canvasBackground = new NodeContainer(parent.color('backgroundColor').isTransparent() ? element.ownerDocument.body : element.ownerDocument.documentElement, null);
Expand Down Expand Up @@ -283,6 +286,9 @@ NodeParser.prototype.paint = function(container) {
}
} catch(e) {
log(e);
if (this.options.strict) {
throw e;
}
}
};

Expand Down
5 changes: 1 addition & 4 deletions src/renderers/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ function CanvasRenderer(width, height) {
this.canvas.height = height;
}
this.ctx = this.canvas.getContext("2d");
if (this.options.background) {
this.rectangle(0, 0, width, height, new Color(this.options.background));
}
this.taintCtx = this.document.createElement("canvas").getContext("2d");
this.ctx.textBaseline = "bottom";
this.variables = {};
Expand All @@ -18,7 +15,7 @@ function CanvasRenderer(width, height) {
CanvasRenderer.prototype = Object.create(Renderer.prototype);

CanvasRenderer.prototype.setFillStyle = function(fillStyle) {
this.ctx.fillStyle = (fillStyle instanceof Color) ? fillStyle.toString() : fillStyle;
this.ctx.fillStyle = typeof(fillStyle) === "object" ? fillStyle.toString() : fillStyle;
return this.ctx;
};

Expand Down
1 change: 1 addition & 0 deletions tests/cases/forms.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<body>
<input type="hidden" value="THIS SHOULD NOT BE VISIBLE!" />
<input type="text" value="textbox" />
<input type="password" value="textbox" />
<input type="text" value="textbox" style="border:5px solid navy;" />
<input type="text" value="textbox" style="border:5px solid navy;height:40px;" />

Expand Down
72 changes: 72 additions & 0 deletions tests/mocha/password-rendering.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<html>
<head>
<meta charset="utf-8">
<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>
<style>
.block {
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<div id="mocha"></div>
<script>mocha.setup('bdd')</script>
<div id="block1" class="block">
<input type="text" value="text" />
</div>
<div id="block2" class="block">
<input type="password" value="password" />
</div>
<div id="green-block"></div>
<script>
describe("Rendering input values", function() {
it("uses default value for input[type='text']", function(done) {
CanvasRenderer.prototype.text = function(text) {
expect(text).to.equal('text');
};
html2canvas(document.querySelector("#block1"), {renderer: CanvasRenderer, strict: true}).then(function(canvas) {
expect(canvas.width).to.equal(200);
expect(canvas.height).to.equal(200);
done();
}).catch(function(error) {
done(error);
});
});

it("uses transformed value for input[type='password']", function(done) {
var count = 0;
CanvasRenderer.prototype.text = function(text) {
expect(text).to.equal('•');
count++;
};
html2canvas(document.querySelector("#block2"), {renderer: CanvasRenderer, strict: true}).then(function(canvas) {
expect(canvas.width).to.equal(200);
expect(canvas.height).to.equal(200);
expect(count).to.equal("password".length);
done();
}).catch(function(error) {
done(error);
});
});
});

mocha.checkLeaks();
mocha.globals(['jQuery']);
if (window.mochaPhantomJS) {
mochaPhantomJS.run();
}
else {
mocha.run();
}
</script>
</body>
</html>

0 comments on commit 4985279

Please sign in to comment.