Merge remote-tracking branch 'niklasvh/develop' into develop

This commit is contained in:
Andy Edinborough 2013-01-11 09:51:59 -06:00
commit d73e53fbf0
5 changed files with 181 additions and 224 deletions

View File

@ -166,6 +166,16 @@ _html2canvas.Parse = function (images, options) {
metrics = setTextVariables(ctx, el, textDecoration, color);
if (options.chinese) {
textList.forEach(function(word, index) {
if (/.*[\u4E00-\u9FA5].*$/.test(word)) {
word = word.split("");
word.unshift(index, 1)
textList.splice.apply(textList, word);
}
});
}
textList.forEach(function(text, index) {
var bounds = getTextBounds(state, text, textDecoration, (index < textList.length - 1));
if (bounds) {

View File

@ -22,7 +22,7 @@ _html2canvas.Renderer = function(parseQueue, options){
stackValues.forEach(function(zValue) {
var index;
subStacks.some(function(stack, i){
index = i;
return (stack.zindex === zValue);
@ -48,11 +48,11 @@ _html2canvas.Renderer = function(parseQueue, options){
throw new Error("Unknown renderer");
}
if ( typeof renderer._create !== "function" ) {
if ( typeof renderer !== "function" ) {
throw new Error("Invalid renderer defined");
}
return renderer;
}
return getRenderer(options.renderer)._create(parseQueue, options, document, createRenderQueue(parseQueue), _html2canvas);
return getRenderer(options.renderer)(parseQueue, options, document, createRenderQueue(parseQueue), _html2canvas);
};

View File

@ -5,6 +5,7 @@ window.html2canvas = function(elements, opts) {
// general
logging: false,
elements: elements,
background: "#fff",
// preload options
proxy: "",
@ -17,10 +18,10 @@ window.html2canvas = function(elements, opts) {
ignoreElements: "IFRAME|OBJECT|PARAM",
useOverflow: true,
letterRendering: false,
chinese: false,
// render options
flashcanvas: undefined, // path to flashcanvas
width: null,
height: null,
taintTest: true, // do a taint test with all images before applying to canvas

View File

@ -1,233 +1,138 @@
_html2canvas.Renderer.Canvas = function( options ) {
_html2canvas.Renderer.Canvas = function(options) {
options = options || {};
var doc = document,
canvas = options.canvas || doc.createElement('canvas'),
usingFlashcanvas = false,
_createCalled = false,
canvasReadyToDraw = false,
methods,
flashMaxSize = 2880; // flash bitmap limited to 2880x2880px // http://stackoverflow.com/questions/2033792/argumenterror-error-2015-invalid-bitmapdata
safeImages = [],
testCanvas = document.createElement("canvas"),
testctx = testCanvas.getContext("2d"),
canvas = options.canvas || doc.createElement('canvas');
if (canvas.getContext){
h2clog("html2canvas: Renderer: using canvas renderer");
canvasReadyToDraw = true;
} else if ( options.flashcanvas !== undefined ){
usingFlashcanvas = true;
h2clog("html2canvas: Renderer: canvas not available, using flashcanvas");
var script = doc.createElement("script");
script.src = options.flashcanvas;
script.onload = (function(script, func){
var intervalFunc;
if (script.onload === undefined) {
// IE lack of support for script onload
if( script.onreadystatechange !== undefined ) {
intervalFunc = function() {
if (script.readyState !== "loaded" && script.readyState !== "complete") {
window.setTimeout( intervalFunc, 250 );
} else {
// it is loaded
func();
}
};
window.setTimeout( intervalFunc, 250 );
} else {
h2clog("html2canvas: Renderer: Can't track when flashcanvas is loaded");
}
} else {
return func;
}
})(script, function(){
if (typeof window.FlashCanvas !== "undefined") {
h2clog("html2canvas: Renderer: Flashcanvas initialized");
window.FlashCanvas.initElement( canvas );
canvasReadyToDraw = true;
if ( _createCalled !== false ) {
methods._create.apply( null, _createCalled );
}
}
function createShape(ctx, args) {
ctx.beginPath();
args.forEach(function(arg) {
ctx[arg.name].apply(ctx, arg['arguments']);
});
doc.body.appendChild( script );
ctx.closePath();
}
methods = {
_create: function( zStack, options, doc, queue, _html2canvas ) {
if ( !canvasReadyToDraw ) {
_createCalled = arguments;
return canvas;
function safeImage(item) {
if (safeImages.indexOf(item['arguments'][0].src ) === -1) {
testctx.drawImage(item['arguments'][0], 0, 0);
try {
testctx.getImageData(0, 0, 1, 1);
} catch(e) {
testCanvas = doc.createElement("canvas");
testctx = testCanvas.getContext("2d");
return false;
}
var ctx = canvas.getContext("2d"),
storageContext,
i,
queueLen,
a,
newCanvas,
bounds,
testCanvas = document.createElement("canvas"),
hasCTX = ( testCanvas.getContext !== undefined ),
storageLen,
renderItem,
testctx = ( hasCTX ) ? testCanvas.getContext("2d") : {},
safeImages = [],
fstyle;
canvas.width = canvas.style.width = (!usingFlashcanvas) ? options.width || zStack.ctx.width : Math.min(flashMaxSize, (options.width || zStack.ctx.width) );
canvas.height = canvas.style.height = (!usingFlashcanvas) ? options.height || zStack.ctx.height : Math.min(flashMaxSize, (options.height || zStack.ctx.height) );
fstyle = ctx.fillStyle;
ctx.fillStyle = (zStack.backgroundColor === "transparent" || zStack.backgroundColor === "rgba(0, 0, 0, 0)") ? "#fff" : zStack.backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = fstyle;
var createShape = function(args) {
ctx.beginPath();
args.forEach(function(arg) {
ctx[arg.name].apply(ctx, arg['arguments']);
});
ctx.closePath();
};
if ( options.svgRendering && zStack.svgRender !== undefined ) {
// TODO: enable async rendering to support this
ctx.drawImage( zStack.svgRender, 0, 0 );
} else {
for ( i = 0, queueLen = queue.length; i < queueLen; i+=1 ) {
storageContext = queue.splice(0, 1)[0];
storageContext.canvasPosition = storageContext.canvasPosition || {};
//this.canvasRenderContext(storageContext,parentctx);
// set common settings for canvas
ctx.textBaseline = "bottom";
if (storageContext.clip){
ctx.save();
ctx.beginPath();
// console.log(storageContext);
ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
ctx.clip();
}
if (storageContext.ctx.storage){
for (a = 0, storageLen = storageContext.ctx.storage.length; a < storageLen; a+=1){
renderItem = storageContext.ctx.storage[a];
switch(renderItem.type){
case "variable":
ctx[renderItem.name] = renderItem['arguments'];
break;
case "function":
if (renderItem.name === "fillRect") {
if (!usingFlashcanvas || renderItem['arguments'][0] + renderItem['arguments'][2] < flashMaxSize && renderItem['arguments'][1] + renderItem['arguments'][3] < flashMaxSize) {
ctx.fillRect.apply( ctx, renderItem['arguments'] );
}
} else if (renderItem.name === "createPattern") {
ctx.fillStyle = ctx.createPattern(renderItem['arguments'][0], "repeat");
} else if (renderItem.name === "drawShape") {
createShape(renderItem['arguments']);
} else if (renderItem.name === "fillText") {
if (!usingFlashcanvas || renderItem['arguments'][1] < flashMaxSize && renderItem['arguments'][2] < flashMaxSize) {
ctx.fillText.apply( ctx, renderItem['arguments'] );
}
} else if (renderItem.name === "drawImage") {
if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7] > 0) {
if ( hasCTX && options.taintTest ) {
if ( safeImages.indexOf( renderItem['arguments'][ 0 ].src ) === -1 ) {
testctx.drawImage( renderItem['arguments'][ 0 ], 0, 0 );
try {
testctx.getImageData( 0, 0, 1, 1 );
} catch(e) {
testCanvas = doc.createElement("canvas");
testctx = testCanvas.getContext("2d");
continue;
}
safeImages.push( renderItem['arguments'][ 0 ].src );
}
}
ctx.drawImage.apply( ctx, renderItem['arguments'] );
}
} else {
ctx[renderItem.name].apply(ctx, renderItem['arguments']);
}
break;
default:
}
}
}
if (storageContext.clip){
ctx.restore();
}
}
}
h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj");
queueLen = options.elements.length;
if (queueLen === 1) {
if (typeof options.elements[ 0 ] === "object" && options.elements[ 0 ].nodeName !== "BODY" && usingFlashcanvas === false) {
// crop image to the bounds of selected (single) element
bounds = _html2canvas.Util.Bounds( options.elements[ 0 ] );
newCanvas = doc.createElement('canvas');
newCanvas.width = bounds.width;
newCanvas.height = bounds.height;
ctx = newCanvas.getContext("2d");
ctx.drawImage( canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height );
canvas = null;
return newCanvas;
}
} /*else {
// TODO clip and resize multiple elements
for ( i = 0; i < queueLen; i+=1 ) {
if (options.elements[ i ] instanceof Element) {
}
}
}
*/
return canvas;
safeImages.push(item['arguments'][0].src);
}
return true;
}
function isTransparent(backgroundColor) {
return (backgroundColor === "transparent" || backgroundColor === "rgba(0, 0, 0, 0)");
}
function renderItem(ctx, item) {
switch(item.type){
case "variable":
ctx[item.name] = item['arguments'];
break;
case "function":
if (item.name === "createPattern") {
if (item['arguments'][0].width > 0 && item['arguments'][0].height > 0) {
try {
ctx.fillStyle = ctx.createPattern(item['arguments'][0], "repeat");
}
catch(e) {
h2clog("html2canvas: Renderer: Error creating pattern", e.message);
}
}
} else if (item.name === "drawShape") {
createShape(ctx, item['arguments']);
} else if (item.name === "drawImage") {
if (item['arguments'][8] > 0 && item['arguments'][7] > 0) {
if (options.taintTest || (options.taintTest && safeImage(item))) {
ctx.drawImage.apply( ctx, item['arguments'] );
}
}
} else {
ctx[item.name].apply(ctx, item['arguments']);
}
break;
}
}
return function(zStack, options, doc, queue, _html2canvas) {
var ctx = canvas.getContext("2d"),
storageContext,
i,
queueLen,
newCanvas,
bounds,
fstyle;
canvas.width = canvas.style.width = options.width || zStack.ctx.width;
canvas.height = canvas.style.height = options.height || zStack.ctx.height;
fstyle = ctx.fillStyle;
ctx.fillStyle = (isTransparent(zStack.backgroundColor) && options.background !== undefined) ? options.background : zStack.backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = fstyle;
if ( options.svgRendering && zStack.svgRender !== undefined ) {
// TODO: enable async rendering to support this
ctx.drawImage( zStack.svgRender, 0, 0 );
} else {
for ( i = 0, queueLen = queue.length; i < queueLen; i+=1 ) {
storageContext = queue.splice(0, 1)[0];
storageContext.canvasPosition = storageContext.canvasPosition || {};
// set common settings for canvas
ctx.textBaseline = "bottom";
if (storageContext.clip){
ctx.save();
ctx.beginPath();
// console.log(storageContext);
ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
ctx.clip();
}
if (storageContext.ctx.storage) {
storageContext.ctx.storage.forEach(renderItem.bind(null, ctx));
}
if (storageContext.clip){
ctx.restore();
}
}
}
h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj");
queueLen = options.elements.length;
if (queueLen === 1) {
if (typeof options.elements[0] === "object" && options.elements[0].nodeName !== "BODY") {
// crop image to the bounds of selected (single) element
bounds = _html2canvas.Util.Bounds(options.elements[0]);
newCanvas = doc.createElement('canvas');
newCanvas.width = bounds.width;
newCanvas.height = bounds.height;
ctx = newCanvas.getContext("2d");
ctx.drawImage(canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height);
canvas = null;
return newCanvas;
}
}
return canvas;
};
return methods;
};

View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<title>Chinese text</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../../test.js"></script>
<script>
h2cOptions = {
chinese: true
}
</script>
<style>
.chn-text-block {
width: 500px;
font-family: serif;
float: left;
}
</style>
</head>
<body>
<div id="text" class="chn-text-block">
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;1 见本书第一卷《实践论》注6
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;2 见列宁《党的组织和党的出版物》。列宁在这篇论文中说“这将是自由的写作因为把一批又一批新生力量吸引到写作队伍中来的不是私利贪欲也不是名誉地位而是社会主义思想和对劳动人民的同情。这将是自由的写作因为它不是为饱食终日的贵妇人服务不是为百无聊赖、胖得发愁的一万个上层分子服务而是为千千万万劳动人民为这些国家的精华、国家的力量、国家的未来服务。这将是自由的写作它要用社会主义无产阶级的经验和生气勃勃的工作去丰富人类革命思想的最新成就它要使过去的经验从原始空想的社会主义发展而成的科学社会主义和现在的经验工人同志们当前的斗争之间经常发生相互作用。”《列宁全集》第12卷人民出版社1987年版第96—97页
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;3 梁实秋一九○三——一九八七北京人。新月社主要成员。先后在复旦大学、北京大学等校任教。曾写过一些文艺评论长时期致力于文学翻译工作和散文的写作。鲁迅对梁实秋的批评见《三闲集·新月社批评家的任务》、《二心集·“硬译”与“文学的阶级性”》等文。《鲁迅全集》第4卷人民文学出版社1981年版第159、195—212页
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;4 周作人(一八八五——一九六七),浙江绍兴人。曾在北京大学、燕京大学等校任教。五四运动时从事新文学写作。他的著述很多,有大量的散文集、文学专著和翻译作品。张资平(一八九三——一九五九),广东梅县人。他写过很多小说,曾在暨南大学、大夏大学兼任教职。周作人、张资平于一九三八年和一九三九年先后在北平、上海依附侵略中国的日本占领者。
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;5 见鲁迅《二心集·对于左翼作家联盟的意见》《鲁迅全集》第4卷人民文学出版社1981年版第237—238页
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;6 参见鲁迅《且介亭杂文末编·附集·死》《鲁迅全集》第6卷人民文学出版社1981年版第612页
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;7 “小放牛”是中国一出传统的小歌舞剧。全剧只有两个角色,男角是牧童,女角是乡村小姑娘,以互相对唱的方式表现剧的内容。抗日战争初期,革命的文艺工作者利用这个歌舞剧的形式,变动其原来的词句,宣传抗日,一时颇为流行。
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;8 “人、手、口、刀、牛、羊”是笔画比较简单的汉字,旧时一些小学国语读本把这几个字编在第一册的最初几课里。
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;9 “阳春白雪”和“下里巴人”,都是公元前三世纪楚国的歌曲。“阳春白雪”是供少数人欣赏的较高级的歌曲;“下里巴人”是流传很广的民间歌曲。《文选·宋玉对楚王问》记载一个故事,说有人在楚都唱歌,唱“阳春白雪”时,“国中属而和者(跟着唱的),不过数十人”;但唱“下里巴人”时,“国中属而和者数千人”。
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;10 见列宁《党的组织和党的出版物》。列宁在这篇论文中说“写作事业应当成为整个无产阶级事业的一部分成为由整个工人阶级的整个觉悟的先锋队所开动的一部巨大的社会民主主义机器的齿轮和螺丝钉。”《列宁全集》第12卷人民出版社1987年版第93页
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;11 亭子间是上海里弄房子中的一种小房间,位置在房子后部的楼梯中侧,狭小黑暗,因此租金比较低廉。解放以前,贫苦的作家、艺术家、知识分子和机关小职员,多半租这种房间居住。
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;12 见本书第二卷《和中央社、扫荡报、新民报三记者的谈话》注3
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;13 法捷耶夫(一九○一——一九五六),苏联名作家。他所作的小说《毁灭》于一九二七年出版,内容是描写苏联国内战争时期由苏联远东滨海边区工人、农民和革命知识分子所组成的一支游击队同国内反革命白卫军以及日本武装干涉军进行斗争的故事。这部小说曾由鲁迅译为汉文。
</p><p>&nbsp;&nbsp;&nbsp;&nbsp;14 见鲁迅《集外集·自嘲》《鲁迅全集》第7卷人民文学出版社1981年版第147页</p>
</div>
</body>
</html>