| Index: experimental/docs/canvasBackend.js | 
| diff --git a/experimental/docs/canvasBackend.js b/experimental/docs/canvasBackend.js | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..0574813f2224b952fb9903bfdbed6aedf6785ede | 
| --- /dev/null | 
| +++ b/experimental/docs/canvasBackend.js | 
| @@ -0,0 +1,167 @@ | 
| +var canvas; | 
| +var ctx; | 
| +var canvasGradients = {}; | 
| + | 
| +function canvas_rbga(color) { | 
| +    var a = canvas_opacity(color); | 
| +    var r = (color >> 16) & 0xFF; | 
| +    var g = (color >>  8) & 0xFF; | 
| +    var b = (color >>  0) & 0xFF; | 
| +    return "rgba(" + r + "," + g + "," + b + "," + a + ")"; | 
| +} | 
| + | 
| +function canvas_opacity(color) { | 
| +    var a = (color >> 24) & 0xFF; | 
| +    return a / 255.; | 
| +} | 
| + | 
| +function displayCanvas(displayList) { | 
| +    if (displayList.clear) { | 
| +        ctx.clearRect(0, 0, canvas.width, canvas.height); | 
| +    } | 
| +    for (var index = 0; index < displayList.length; ++index) { | 
| +        drawToCanvas(displayList[index]); | 
| +    } | 
| +} | 
| + | 
| +function drawToCanvas(action) { | 
| +    ctx.save(); | 
| +    var paint = paintToCanvas(action.paint); | 
| +    var draw = action.draw; | 
| +    if ('string' == typeof(draw)) { | 
| +        draw = (new Function("return " + draw))(); | 
| +    } | 
| +    if (isArray(draw)) { | 
| +        assert(draw.length > 0); | 
| +        var picture = 'draw' in draw[0]; | 
| +        if (picture) { | 
| +            for (var index = 0; index < draw.length; ++index) { | 
| +                drawToCanvas(draw[index]); | 
| +            } | 
| +            return; | 
| +        } | 
| +        ctx.beginPath(); | 
| +        for (var index = 0; index < draw.length; ++index) { | 
| +            for (var prop in draw[index]) { | 
| +                var v = draw[index][prop]; | 
| +                switch (prop) { | 
| +                    case 'arcTo': | 
| +                        ctx.arcTo(v[0], v[1], v[2], v[3], v[4]); | 
| +                        break; | 
| +                    case 'close': | 
| +                        ctx.closePath(); | 
| +                        break; | 
| +                    case 'cubic': | 
| +                        ctx.moveTo(v[0], v[1]); | 
| +                        ctx.bezierCurveTo(v[2], v[3], v[4], v[5], v[6], v[7]); | 
| +                        break; | 
| +                    case 'line': | 
| +                        ctx.moveTo(v[0], v[1]); | 
| +                        ctx.lineTo(v[2], v[3]); | 
| +                        break; | 
| +                    case 'quad': | 
| +                        ctx.moveTo(v[0], v[1]); | 
| +                        ctx.quadraticCurveTo(v[2], v[3], v[4], v[5]); | 
| +                        break; | 
| +                    default: | 
| +                        assert(0); | 
| +                } | 
| +            } | 
| +        } | 
| +        if ('fill' == paint.style) { | 
| +            ctx.fill(); | 
| +        } else { | 
| +            assert('stroke' == paint.style); | 
| +            ctx.stroke(); | 
| +        } | 
| +    } else { | 
| +        assert('string' in draw); | 
| +        if ('fill' == paint.style) { | 
| +            ctx.fillText(draw.string, draw.x, draw.y); | 
| +        } else { | 
| +            assert('stroke' == paint.style); | 
| +            ctx.strokeText(draw.string, draw.x, draw.y); | 
| +        } | 
| +    } | 
| +    ctx.restore(); | 
| +} | 
| + | 
| +function keyframeCanvasInit(displayList, first) { | 
| +    if ('canvas' in first && 'clear' == first.canvas) { | 
| +        displayList.clear = true; | 
| +    } | 
| +} | 
| + | 
| +function paintToCanvas(paint) { | 
| +    var color; | 
| +    var inPicture = 'string' == typeof(paint); | 
| +    if (inPicture) { | 
| +        paint = (new Function("return " + paint))(); | 
| +        assert('object' == typeof(paint) && !isArray(paint)); | 
| +    } | 
| +    if ('gradient' in paint) { | 
| +        var gradient = paint.gradient.split('.'); | 
| +        var gradName = gradient[1]; | 
| +        if (!canvasGradients[gradName]) { | 
| +            var g = window[gradient[0]][gradient[1]]; | 
| +            var grad = ctx.createRadialGradient(g.cx, g.cy, 0, g.cx, g.cy, g.r); | 
| +            var stopLen = g.stops.length; | 
| +            for (var index = 0; index < stopLen; ++index) { | 
| +                var stop = g.stops[index]; | 
| +                var color = canvas_rbga(stop.color); | 
| +                grad.addColorStop(index, color); | 
| +            } | 
| +            canvasGradients[gradName] = grad; | 
| +        } | 
| +        color = canvasGradients[gradName]; | 
| +        if (!inPicture) { | 
| +            ctx.globalAlpha = canvas_opacity(paint.color); | 
| +        } | 
| +    } else { | 
| +        color = canvas_rbga(paint.color); | 
| +    } | 
| +    if ('fill' == paint.style) { | 
| +        ctx.fillStyle = color; | 
| +    } else if ('stroke' == paint.style) { | 
| +        ctx.strokeStyle = color; | 
| +    } else { | 
| +        ctx.globalAlpha = canvas_opacity(paint.color); | 
| +    } | 
| +    if ('strokeWidth' in paint) { | 
| +        ctx.lineWidth = paint.strokeWidth; | 
| +    } | 
| +    if ('typeface' in paint) { | 
| +        var typeface = typefaces[paint.typeface]; | 
| +        var font = typeface.style; | 
| +        if ('textSize' in paint) { | 
| +            font += " " + paint.textSize; | 
| +        } | 
| +        if ('family' in typeface) { | 
| +            font += " " + typeface.family; | 
| +        } | 
| +        ctx.font = font; | 
| +        if ('textAlign' in paint) { | 
| +            ctx.textAlign = paint.textAlign; | 
| +        } | 
| +        if ('textBaseline' in paint) { | 
| +            ctx.textBaseline = paint.textBaseline; | 
| +        } | 
| +    } | 
| +    return paint; | 
| +} | 
| + | 
| +function setupCanvas() { | 
| +    canvas = document.getElementById("canvas"); | 
| +    ctx = canvas ? canvas.getContext("2d") : null; | 
| +    assert(ctx); | 
| +    var resScale = window.devicePixelRatio ? window.devicePixelRatio : 1; | 
| +    var unscaledWidth = canvas.width; | 
| +    var unscaledHeight = canvas.height; | 
| +    canvas.width = unscaledWidth * resScale; | 
| +    canvas.height = unscaledHeight * resScale; | 
| +    canvas.style.width = unscaledWidth + 'px'; | 
| +    canvas.style.height = unscaledHeight + 'px'; | 
| +    if (resScale != 1) { | 
| +        ctx.scale(resScale, resScale); | 
| +    } | 
| +} | 
|  |