Skip to content

Commit 9beae48

Browse files
committed
Start implementing background gradients
1 parent 1773116 commit 9beae48

9 files changed

Lines changed: 108 additions & 29 deletions

File tree

.jshintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
"jQuery": true
1515
},
1616
"predef": ["NodeParser", "NodeContainer", "StackingContext", "TextContainer", "ImageLoader", "CanvasRenderer", "Renderer", "Support", "bind", "Promise",
17-
"ImageContainer", "ProxyImageContainer", "DummyImageContainer", "Font", "FontMetrics", "log", "smallImage"]
17+
"ImageContainer", "ProxyImageContainer", "DummyImageContainer", "Font", "FontMetrics", "GradientContainer", "LinearGradientContainer", "WebkitGradientContainer", "log", "smallImage"]
1818
}

src/gradientcontainer.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function GradientContainer(imageData) {
2+
this.src = imageData.value;
3+
this.colorStops = [];
4+
this.type = null;
5+
this.x0 = 0.5;
6+
this.y0 = 0.5;
7+
this.x1 = 0.5;
8+
this.y1 = 0.5;
9+
this.promise = Promise.resolve(true);
10+
}
11+
12+
GradientContainer.prototype.TYPES = {
13+
LINEAR: 1,
14+
RADIAL: 2
15+
};

src/imageloader.js

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,41 @@ ImageLoader.prototype.findImages = function(nodes) {
1212
};
1313

1414
ImageLoader.prototype.findBackgroundImage = function(images, container) {
15-
container.parseBackgroundImages().filter(this.isImageBackground).map(this.getBackgroundUrl).forEach(this.addImage(images, this.loadImage), this);
15+
container.parseBackgroundImages().filter(this.hasImageBackground).forEach(this.addImage(images, this.loadImage), this);
1616
return images;
1717
};
1818

1919
ImageLoader.prototype.addImage = function(images, callback) {
2020
return function(newImage) {
2121
if (!this.imageExists(images, newImage)) {
2222
images.splice(0, 0, callback.apply(this, arguments));
23-
log('Added image #' + (images.length), newImage.substring(0, 100));
23+
log('Added image #' + (images.length), newImage);
2424
}
2525
};
2626
};
2727

28-
ImageLoader.prototype.getBackgroundUrl = function(imageData) {
29-
return imageData.args[0];
28+
ImageLoader.prototype.hasImageBackground = function(imageData) {
29+
return imageData.method !== "none";
3030
};
3131

32-
ImageLoader.prototype.isImageBackground = function(imageData) {
33-
return imageData.method === "url";
34-
};
35-
36-
ImageLoader.prototype.loadImage = function(src) {
37-
if (src.match(/data:image\/.*;base64,/i)) {
38-
return new ImageContainer(src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''), false);
39-
} else if (this.isSameOrigin(src) || this.options.allowTaint === true) {
40-
return new ImageContainer(src, false);
41-
} else if (this.support.cors && !this.options.allowTaint && this.options.useCORS) {
42-
return new ImageContainer(src, true);
43-
} else if (this.options.proxy) {
44-
return new ProxyImageContainer(src);
45-
} else {
46-
return new DummyImageContainer(src);
32+
ImageLoader.prototype.loadImage = function(imageData) {
33+
if (imageData.method === "url") {
34+
var src = imageData.args[0];
35+
if (src.match(/data:image\/.*;base64,/i)) {
36+
return new ImageContainer(src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''), false);
37+
} else if (this.isSameOrigin(src) || this.options.allowTaint === true) {
38+
return new ImageContainer(src, false);
39+
} else if (this.support.cors && !this.options.allowTaint && this.options.useCORS) {
40+
return new ImageContainer(src, true);
41+
} else if (this.options.proxy) {
42+
return new ProxyImageContainer(src);
43+
} else {
44+
return new DummyImageContainer(src);
45+
}
46+
} else if (imageData.method === "linear-gradient") {
47+
return new LinearGradientContainer(imageData);
48+
} else if (imageData.method === "gradient") {
49+
return new WebkitGradientContainer(imageData);
4750
}
4851
};
4952

src/lineargradientcontainer.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
function LinearGradientContainer(imageData) {
2+
GradientContainer.apply(this, arguments);
3+
this.type = this.TYPES.LINEAR;
4+
5+
imageData.args[0].split(" ").forEach(function(position) {
6+
switch(position) {
7+
case "left":
8+
this.x0 = 0;
9+
this.x1 = 1;
10+
break;
11+
case "top":
12+
this.y0 = 0;
13+
this.y1 = 1;
14+
break;
15+
case "right":
16+
this.x0 = 1;
17+
this.x1 = 0;
18+
break;
19+
case "bottom":
20+
this.y0 = 1;
21+
this.y1 = 0;
22+
break;
23+
}
24+
}, this);
25+
26+
imageData.args.slice(1).forEach(function(colorStop) {
27+
// console.log(colorStop, colorStop.match(this.stepRegExp));
28+
}, this);
29+
}
30+
31+
LinearGradientContainer.prototype = Object.create(GradientContainer.prototype);
32+
33+
LinearGradientContainer.prototype.stepRegExp = /((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/;

src/nodeparser.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,13 @@ NodeParser.prototype.getBounds = function(node) {
7373
if (node.getBoundingClientRect) {
7474
var clientRect = node.getBoundingClientRect();
7575
var isBody = node.nodeName === "BODY";
76+
var width = isBody ? node.scrollWidth : node.offsetWidth;
7677
return {
7778
top: clientRect.top,
7879
bottom: clientRect.bottom || (clientRect.top + clientRect.height),
80+
right: clientRect.left + width,
7981
left: clientRect.left,
80-
width: isBody ? node.scrollWidth : node.offsetWidth,
82+
width: width,
8183
height: isBody ? node.scrollHeight : node.offsetHeight
8284
};
8385
}

src/renderer.js

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,26 @@ Renderer.prototype.renderBorder = function(data) {
5151
Renderer.prototype.renderBackgroundImage = function(container, bounds) {
5252
var backgroundImages = container.parseBackgroundImages();
5353
backgroundImages.reverse().forEach(function(backgroundImage, index, arr) {
54-
if (backgroundImage.method === "url") {
55-
var image = this.images.get(backgroundImage.args[0]);
56-
if (image) {
57-
this.renderBackgroundRepeating(container, bounds, image, arr.length - (index+1));
58-
} else {
59-
log("Error loading background-image", backgroundImage.args[0]);
60-
}
54+
switch(backgroundImage.method) {
55+
case "url":
56+
var image = this.images.get(backgroundImage.args[0]);
57+
if (image) {
58+
this.renderBackgroundRepeating(container, bounds, image, arr.length - (index+1));
59+
} else {
60+
log("Error loading background-image", backgroundImage.args[0]);
61+
}
62+
break;
63+
case "linear-gradient":
64+
case "gradient":
65+
var gradientImage = this.images.get(backgroundImage.value);
66+
if (gradientImage) {
67+
this.renderBackgroundGradient(gradientImage, bounds);
68+
} else {
69+
log("Error loading background-image", backgroundImage.args[0]);
70+
}
71+
break;
72+
default:
73+
log("Unknown background-image type", backgroundImage.args[0]);
6174
}
6275
}, this);
6376
};

src/renderers/canvas.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ CanvasRenderer.prototype.renderBackgroundRepeat = function(imageContainer, backg
9696
this.ctx.translate(-offsetX, -offsetY);
9797
};
9898

99+
CanvasRenderer.prototype.renderBackgroundGradient = function(gradientImage, bounds) {
100+
if (gradientImage instanceof LinearGradientContainer) {
101+
var gradient = this.ctx.createLinearGradient(bounds.left, bounds.top, bounds.right, bounds.bottom);
102+
//console.log(gradientImage, bounds, gradient);
103+
}
104+
};
105+
99106
CanvasRenderer.prototype.resizeImage = function(imageContainer, size) {
100107
var image = imageContainer.image;
101108
if(image.width === size.width && image.height === size.height) {

src/webkitgradientcontainer.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
function WebkitGradientContainer(imageData) {
2+
GradientContainer.apply(this, arguments);
3+
this.type = (imageData.args[0] === "linear") ? this.TYPES.LINEAR : this.TYPES.RADIAL;
4+
}
5+
6+
WebkitGradientContainer.prototype = Object.create(GradientContainer.prototype);

tests/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ var h2cSelector, h2cOptions;
1111

1212
document.write(srcStart + '/tests/assets/jquery-1.6.2.js' + scrEnd);
1313
document.write(srcStart + '/tests/assets/jquery.plugin.html2canvas.js' + scrEnd);
14-
var html2canvas = ['log', 'nodecontainer', 'stackingcontext', 'textcontainer', 'support', 'imagecontainer',
14+
var html2canvas = ['log', 'nodecontainer', 'stackingcontext', 'textcontainer', 'support', 'imagecontainer', 'gradientcontainer', 'lineargradientcontainer', 'webkitgradientcontainer',
1515
'imageloader', 'nodeparser', 'font', 'fontmetrics', 'core', 'renderer', 'promise', 'renderers/canvas'], i;
1616
for (i = 0; i < html2canvas.length; ++i) {
1717
document.write(srcStart + '/src/' + html2canvas[i] + '.js?' + Math.random() + scrEnd);

0 commit comments

Comments
 (0)