<!DOCTYPE html>
<html>
<head>
<style type='text/css'>
body { background: red; }
#zoom { margin-left: 680px; }
</style>
<script>

// This function has problems with paths that include multiple subpaths.
// First, if the boundaries of two subpaths are close, and
// the stroke outside of one would be inside of the other, then we can
// get artifacts.  
// Second, when one subpath is entirely enclosed inside the other and
// the windings are the same, then both the inside and outside of the
// inner subpath are "inside".  So should we stroke both sides?
// That is what this method does.  It seems kind of logical, but not really
// what we'd want.
//
// The upshot is that strokeInside() is not a fully-general replacement for
// stroke().  When multiple subpaths are required they may need to be 
// stroked individually rather than as a group.
function strokeInside(c) {
    c.save();
    c.clip();
    c.lineWidth *= 2;
    c.stroke();
    c.restore();
}

function strokeOutside(c) {
    // Back up the entire canvas to an offscreen canvas
    var offscreen = document.createElement("canvas");
    offscreen.width = c.canvas.width;
    offscreen.height = c.canvas.height;
    var offC = offscreen.getContext('2d');
    offC.drawImage(c.canvas, 0, 0);

    // Save current state
    c.save();

    // Stroke the shape with double linewidth
    c.lineWidth *= 2;
    c.stroke();

    // Now set the clipping region and restore the interior of the path
    // to its original state before the stroke
    c.clip();
    c.globalCompositeOperation = "copy";  // So we don't blend colors
    c.setTransform(1,0,0,1,0,0);          // Back to default coordinate system
    c.drawImage(offscreen, 0, 0);         // Copy the image back

    // Restore the graphics state
    c.restore();

    // Deallocate offscreen pixels?
    offscreen.width = offscreen.height = 0;
}

function shape(c) {
    c.beginPath();

    c.moveTo(100,10);
    c.lineTo(140,170);
    c.lineTo(10,40);
    c.lineTo(150,40);
    c.lineTo(60,175);
    c.closePath();

    c.rect(0,200,200,150);

    c.moveTo(65,265);
    c.arc(65,265,50,0,Math.PI/3,true);
    c.closePath();

    c.moveTo(130,280);
    c.arc(130,280,50,0,Math.PI/3,false);
    c.closePath();

    c.fill();
    c.save();
    c.lineWidth = arguments[1] || 0;
    c.strokeStyle = c.fillStyle;
    c.stroke();
    c.restore();
}

function demo() {
    var canvas  = document.getElementById("canvas");
    var c = canvas.getContext('2d');

    c.fillStyle = "rgba(246,246,246,1)";
    c.strokeStyle = "rgba(150,150,150,1)";
    c.lineWidth = 8;

  
    c.translate(20,20);
    shape(c);
    c.stroke();       // Regular stroke


    // What does it mean to stroke inside a path when subpaths overlap?
    // if both sides of a subpath are inside a containing path, should
    // both sides be stroked?
    c.translate(250, 0);
    shape(c);
    strokeInside(c);  // Stroke inside the path

    c.translate(250, 0);
    shape(c);
    strokeOutside(c); // Stroke outside the path

                c.translate(250, 0);
    shape(c, 1);
    strokeOutside(c); // Stroke outside the path with a 1px stroke on the shape, only fixes firefox
}

window.onload = demo;
</script>
</head>
<body>
<canvas id="canvas" width=980 height=450></canvas>
<p>
<img id='zoom' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIMAAABfCAYAAADLYXQyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAxhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDM0MiwgMjAxMC8wMS8xMC0xODowNjo0MyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo0NjAyMzk1MDk3MTkxMURGODU2QkZGOTgxMDYwNTREOSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo0NjAyMzk1MTk3MTkxMURGODU2QkZGOTgxMDYwNTREOSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjQ2MDIzOTRFOTcxOTExREY4NTZCRkY5ODEwNjA1NEQ5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjQ2MDIzOTRGOTcxOTExREY4NTZCRkY5ODEwNjA1NEQ5Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+qZlBLAAAC2VJREFUeNrsXc1uFDkQ7vmfTGZCsiQr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%3D' alt=''/>
</p>
</body>
</html>