=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js	2020-10-09 18:00:55 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js	2020-10-12 06:09:17 +0000
@@ -651,6 +651,10 @@
    {
       for (var i = 0; i < lastClip.length; i++)
       {
+         if (lastClip[i].height == 0 || lastClip[i].width == 0)
+         {
+            console.error("clipRegion: " + lastClip[i].width + "x" + lastClip[i].height);
+         }
          var top    = lastClip[i].y;
          var bottom = lastClip[i].y + Math.max(lastClip[i].height - 1, 0);
          var left   = lastClip[i].x;
@@ -868,7 +872,7 @@
  */
 CanvasRenderer.prototype.drawCanvas = function(canvas, xDest, yDest, width, height)
 {
-   this.offscreenCtx.drawImage(canvas, xDest, yDest, width, height);
+   this.offscreenCtx.drawImage(canvas, 0, 0, width, height, xDest, yDest, width, height);
 };
 
 /**
@@ -891,22 +895,27 @@
  */
 CanvasRenderer.prototype.drawCanvas = function(canvas, xDest, yDest, width, height, cop, alpha)
 {
-   //save these global values
-   var gcop = this.offscreenCtx.globalCompositeOperation;
-   var galpha = this.offscreenCtx.globalAlpha;
-   if (cop)
+   var gcop;
+   var galpha;
+   var test = (cop) && (alpha);
+   
+   if (test)
    {
+      //save these global values
+      gcop = this.offscreenCtx.globalCompositeOperation;
+      galpha = this.offscreenCtx.globalAlpha;
       this.offscreenCtx.globalCompositeOperation = cop;
-   }
-   if (alpha)
-   {
       this.offscreenCtx.globalAlpha = alpha;
    }
    
-   this.offscreenCtx.drawImage(canvas, xDest, yDest, width, height);
-   // restore the global values for composite operation
-   this.offscreenCtx.globalCompositeOperation = gcop;
-   this.offscreenCtx.globalAlpha = galpha;
+   this.offscreenCtx.drawImage(canvas, 0, 0, width, height, xDest, yDest, width, height);
+   
+   if (test)
+   {
+      // restore the global values for composite operation
+      this.offscreenCtx.globalCompositeOperation = gcop;
+      this.offscreenCtx.globalAlpha = galpha;
+   }
 };
 
 /**
@@ -955,13 +964,37 @@
       // if dy == 0, then a line (x1, y1, x2, y2) is a horizontal
       if (dx === 0 || dy === 0)
       {
+//         if (x2 < x1)
+//         {
+//            var a = x1;
+//            x1 = x2;
+//            x2 = a;
+//         }
+//         
+//         if (y2 < y1)
+//         {
+//            var a = y1;
+//            y1 = y2;
+//            y2 = a;
+//         }
+         
          // to draw a line as an image for the default stroke and widen stroke styles
          // we have x2 >= x1 and y2 >= y1 and dx or dy equals zero.
-         strokeRenderer.strokeLine(x1, y1, x2, y2);//optimization
+         strokeRenderer.strokeLine(x1-this.origin.x, y1-this.origin.y, x2-this.origin.x, y2-this.origin.y);//optimization
       }
       else
       {
-         this.drawSlopedLineSegment(x1, y1, x2, y2, strokeRenderer);
+//         if (x2 < x1)
+//         {
+//            var a = x1;
+//            x1 = x2;
+//            x2 = a;
+//            a = y1;
+//            y1 = y2;
+//            y2 = a;
+//         }
+         
+         this.drawSlopedLineSegment(x1-this.origin.x, y1-this.origin.y, x2-this.origin.x, y2-this.origin.y, strokeRenderer);
       }
    }
 };
@@ -1058,9 +1091,34 @@
 CanvasRenderer.prototype.drawLine = function(x1, y1, x2, y2, color)
 {
    var strokeRenderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
-         this.strokeWidth, color);
-   strokeRenderer.beginStroke();
+         this.strokeWidth, color).setWorkingCanvas(this.tmpCanvas, this.tmpCtx);
+   var rx1, ry1, rx2, ry2;
+   if (x1 > x2)
+   {
+      rx1 = x2;
+      rx2 = x1;
+   }
+   else
+   {
+      rx1 = x1;
+      rx2 = x2;
+   }
+   if (y1 > y2)
+   {
+      ry1 = y2;
+      ry2 = y1;
+   }
+   else
+   {
+      ry1 = y1;
+      ry2 = y2;
+   }
+   this.tmpCanvas.width = rx2 - rx1 + this.strokeWidth;
+   this.tmpCanvas.height = ry2 - ry1 + this.strokeWidth;
+   strokeRenderer.setScreenImage(this.tmpCtx.createImageData(this.tmpCanvas.width, this.tmpCanvas.height));
+   strokeRenderer.beginStroke(rx1, ry1, rx2, ry2);
    this.drawLineSegment(x1, y1, x2, y2, strokeRenderer);
+   strokeRenderer.endStroke();
 }
 
 /**
@@ -1121,9 +1179,34 @@
 CanvasRenderer.prototype.strokeLineSegment = function(x1, y1, x2, y2, color)
 {
    var strokeRenderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
-         this.strokeWidth, color);
-   strokeRenderer.beginStroke();
+         this.strokeWidth, color).setWorkingCanvas(this.tmpCanvas, this.tmpCtx);
+   var rx1, ry1, rx2, ry2;
+   if (x1 > x2)
+   {
+      rx1 = x2;
+      rx2 = x1;
+   }
+   else
+   {
+      rx1 = x1;
+      rx2 = x2;
+   }
+   if (y1 > y2)
+   {
+      ry1 = y2;
+      ry2 = y1;
+   }
+   else
+   {
+      ry1 = y1;
+      ry2 = y2;
+   }
+   this.tmpCanvas.width = rx2 - rx1 + this.strokeWidth;
+   this.tmpCanvas.height = ry2 - ry1 + this.strokeWidth;
+   strokeRenderer.setScreenImage(this.tmpCtx.createImageData(this.tmpCanvas.width, this.tmpCanvas.height));
+   strokeRenderer.beginStroke(rx1, ry1, rx2, ry2);
    this.drawLineSegment(x1, y1, x2, y2, strokeRenderer);
+   strokeRenderer.endStroke();
 }
 
 /**
@@ -1160,12 +1243,15 @@
    // now overdraw the stroked portion to eliminate anti-aliasing, we draw in a
    // clockwise direction (since we are not using paths, this is not strictly necessary)
    var renderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
-         this.strokeWidth, color);
-   renderer.beginStroke();
+         this.strokeWidth, color).setWorkingCanvas(this.tmpCanvas, this.tmpCtx).setScreenImage(undefined);
+   this.tmpCanvas.width = width - inset + this.strokeWidth;
+   this.tmpCanvas.height = height - inset + this.strokeWidth;
+   renderer.beginStroke(x, y, x + width - inset, y + height - inset);
    this.drawLineSegment(x, y, x + width - inset, y, renderer);
    this.drawLineSegment(x + width - inset, y + 1, x + width - inset, y + height - inset, renderer);
    this.drawLineSegment(x + width - 1 - inset, y + height - inset, x + 1, y + height - inset, renderer);
    this.drawLineSegment(x, y + height - inset, x, y + 1, renderer);// close the path
+   renderer.endStroke();
 };
 
 /**
@@ -1189,6 +1275,29 @@
 CanvasRenderer.prototype.strokeRect = function(x, y, width, height, color, fill)
 {
    // filled rectangles draw 1 pixel smaller in 2 dimensions than stroked rectangles
+   if (width == 0 || height == 0)
+   {
+      /*
+      this.offscreenCtx.save();
+      this.offscreenCtx.strokeStyle = "yellow";
+      this.offscreenCtx.strokeWidth = 1;
+      this.offscreenCtx.beginPath();
+      this.offscreenCtx.rect(x, y, width, height);
+      this.offscreenCtx.stroke();
+      this.offscreenCtx.restore();
+      console.error("x = " + x + " y = " + y + " width = " + width + " height = " + height);
+      return;
+      */
+      if (width > 0)
+      {
+         height = 1;
+      }
+      else if (height > 0)
+      {
+         width = 1;
+      }
+   }
+   
    var inset = 0;
    // use vector operations for the interior of the rectangle
    if (fill)
@@ -1202,15 +1311,19 @@
    // now overdraw the stroked portion to eliminate anti-aliasing, we draw in a
    // clockwise direction (since we are not using paths, this is not strictly necessary)
    var renderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
-         this.strokeWidth, color);
-   
-   renderer.beginStroke();
+         this.strokeWidth, color).setWorkingCanvas(this.tmpCanvas, this.tmpCtx).setScreenImage(undefined);
+   
+   this.tmpCanvas.width = width - inset + this.strokeWidth;
+   this.tmpCanvas.height = height - inset +  this.strokeWidth;
+   
+   renderer.beginStroke(x, y, x + width - inset, y + height - inset);
    this.drawLineSegment(x, y, x + width - inset, y, renderer);
    this.drawLineSegment(x + width - inset, y + 1, x + width - inset, y + height - inset,
                         renderer);
    this.drawLineSegment(x + width - 1 - inset, y + height - inset, x + 1, y + height - inset,
                         renderer);
    this.drawLineSegment(x, y + height - inset, x, y + 1, renderer);// close the path
+   renderer.endStroke();
 };
 
 /**
@@ -1361,21 +1474,19 @@
  *           The coppied image width.
  * @param    {Number} height
  *           The coppied image height.
- * @param    {Number} imgDataOffset
- *           The coppied image data offset from the 0-index of its data array, imgData.
  * 
  * @return   {Uint8ClampedArray}
  *           Returns the modified screen image data array with the target image.
  *  
  */
-CanvasRenderer.prototype.copyImage = function(img, data, imgData, width, height, imgDataOffset)
+CanvasRenderer.prototype.copyImage = function(img, data, imgData, width, height)
 {
    var awidth  = img.width;
    var aheight = img.height;
    var x = 0;
    var y = 0;
    var pixelsInBytes = awidth * aheight * 4;
-   var offset = imgDataOffset;
+   var offset = 0;
    for (var p = 0; p < pixelsInBytes; offset += 4)
    {
       data[p]     = imgData[offset];
@@ -1468,12 +1579,15 @@
    
    // overdraw the anti-aliased line segments              
    var renderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
-         this.strokeWidth, color);
-   renderer.beginStroke();
+         this.strokeWidth, color).setWorkingCanvas(this.tmpCanvas, this.tmpCtx).setScreenImage(undefined);
+   this.tmpCanvas.width = width + this.strokeWidth;
+   this.tmpCanvas.height = height + this.strokeWidth;
+   renderer.beginStroke(x, y, x + width, y + height);
    this.drawLineSegment(topLeftX, topLeftY, topRightX, topRightY, renderer);
    this.drawLineSegment(rightUpX, rightUpY, rightDownX, rightDownY, renderer);
    this.drawLineSegment(bottomLeftX, bottomLeftY, bottomRightX, bottomRightY, renderer);
    this.drawLineSegment(leftUpX, leftUpY, leftDownX, leftDownY, renderer);
+   renderer.endStroke();
 };
 
 /**
@@ -1583,8 +1697,13 @@
  */
 CanvasRenderer.prototype.drawPolygon = function(xPoints, yPoints, num, color, fill)
 {
+   if (num < 2)
+   {
+      return;
+   }
+   
    var i;
-
+   
    // use vector operations for the interior of the polygon
    if (fill)
    {
@@ -1595,19 +1714,85 @@
          this.offscreenCtx.lineTo(xPoints[i], yPoints[i]);
       }
       this.offscreenCtx.closePath();
+      this.offscreenCtx.fill();
+      this.offscreenCtx.stroke();
       this.renderClosedPath(fill);
-   }
-   var renderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
-         this.strokeWidth, color);
-   renderer.beginStroke();
-
-   // now overdraw the stroked portion
-   for (i = 0; i < (num - 1); i++)
-   {
-      this.drawLineSegment(xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1], renderer);
-   }
-   // close the path
-   this.drawLineSegment(xPoints[num - 1], yPoints[num - 1], xPoints[0], yPoints[0], renderer);
+      
+   }
+//   var renderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
+//         this.strokeWidth, color).setWorkingCanvas(this.tmpCanvas, this.tmpCtx);
+//   
+//   /** Define the minimal rectangle that covers all points */
+//   var rx1, ry1, rx2, ry2;
+//   
+//   var x1, y1, x2, y2;
+//   
+//   x1 = xPoints[0], y1 = yPoints[0], x2 = xPoints[1], y2 = yPoints[1];
+//   
+//   if (x1 > x2)
+//   {
+//      rx1 = x2;
+//      rx2 = x1;
+//   }
+//   else
+//   {
+//      rx1 = x1;
+//      rx2 = x2;
+//   }
+//   
+//   if (y1 > y2)
+//   {
+//      ry1 = y2;
+//      ry2 = y1;
+//   }
+//   else
+//   {
+//      ry1 = y1;
+//      ry2 = y2;
+//   }
+//   
+//   for (i = 2; i < num; i++)
+//   {
+//      x1 = xPoints[i], y1 = yPoints[i];
+//      
+//      if (rx1 > x1)
+//      {
+//         rx1 = x1;
+//      }
+//      
+//      if (ry1 > y1)
+//      {
+//         ry1 = y1;
+//      }
+//      
+//      if (rx2 < x1)
+//      {
+//         rx2 = x1;
+//      }
+//      
+//      if (ry2 < y1)
+//      {
+//         ry2 = y1;
+//      }
+//   }
+//   
+//   this.tmpCanvas.width = rx2 - rx1 + this.strokeWidth;
+//   
+//   this.tmpCanvas.height = ry2 - ry1 + this.strokeWidth;
+//   
+//   renderer.setScreenImage(this.tmpCtx.createImageData(this.tmpCanvas.width, this.tmpCanvas.height));
+//   renderer.beginStroke(rx1, ry1, rx2, ry2);
+//
+//   
+//   // now overdraw the stroked portion
+//   for (i = 0; i < (num - 1); i++)
+//   {
+//      this.drawLineSegment(xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1], renderer);
+//   }
+//   // close the path
+//   this.drawLineSegment(xPoints[num - 1], yPoints[num - 1], xPoints[0], yPoints[0], renderer);
+//   
+//   renderer.endStroke();
 };
 
 /**
@@ -1771,7 +1956,12 @@
  *           The stroke line width.
  */
 CanvasRenderer.prototype.setLineStroke = function(strokeStyleId, width)
-{                               
+{
+   if (width < 1)
+   {
+      width = 1;
+   }
+   
    this.setStrokeStyleId(strokeStyleId);
    this.setStrokeWidth(width);
    this.strokesManager.applyStrokeToCanvas(this.offscreenCtx, strokeStyleId, width);
@@ -1846,7 +2036,14 @@
 
    for (var i = 0; i < newClip.length; i++)
    {
-      this.offscreenCtx.rect(newClip[i].x, newClip[i].y, newClip[i].width, newClip[i].height);
+      if (newClip[i].width != 0 && newClip[i].height != 0)
+      {
+         this.offscreenCtx.rect(newClip[i].x, newClip[i].y, newClip[i].width, newClip[i].height);
+      }
+      else
+      {
+         console.error("clip " + newClip[i].x + ", " + newClip[i].y + ", " + newClip[i].width + ", " + newClip[i].height);
+      }
    }
 
    this.offscreenCtx.clip();
@@ -1976,7 +2173,6 @@
       ya = clipped[i].top;
       xb = clipped[i].right;
       yb = clipped[i].bottom;
-
       // check that it is vertical or horizontal
       if ((x1 == x2) || (y1 == y2))
       {

=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js	2020-10-09 09:08:16 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js	2020-10-11 12:41:43 +0000
@@ -13,6 +13,7 @@
 **                  properly use of the xorLine() function.
 ** 006 SBI 20191002 Changed to use CanvasRenderer.createImageData(width, height).
 ** 007 HC  20200712 Canvas drawing performance improvements.
+** 008 SBI 20201007 Rewrite using functional style, minor improvements in line drawings.
 */
 /*
 ** This program is free software: you can redistribute it and/or modify
@@ -136,20 +137,20 @@
     * Represents a dot style with 2 pixels to draw and then 2 pixels to pass.
     */
    var dotStroke = new BasicStroke(LineStroke.DOT_LINE_WIDTH, CAP_BUTT, JOIN_BEVEL, 0.0,
-         [LineStroke.DOT_STEP, LineStroke.DOT_STEP], LineStroke.DOT_STEP);
+         [LineStroke.DOT_STEP, LineStroke.DOT_STEP], 0);
 
    /**
     * Represents a dot style with 1 pixel to draw and then 1 pixel to pass.
     */
    var dotSmallStroke  = new BasicStroke(LineStroke.DOT_LINE_WIDTH, CAP_BUTT, JOIN_BEVEL, 0.0,
-         [LineStroke.DOT_STEP_SMALL, LineStroke.DOT_STEP_SMALL], LineStroke.DOT_STEP_SMALL);
+         [LineStroke.DOT_STEP_SMALL, LineStroke.DOT_STEP_SMALL], 0);
 
    /**
     * Represents a dot style with 0.5 pixel to draw and then 0.5 pixel to pass.
     */
    var dotSmallThinStroke = new BasicStroke(LineStroke.DOT_LINE_THIN_WIDTH, CAP_BUTT,
          JOIN_BEVEL, 0.0, [LineStroke.DOT_STEP_SMALL, LineStroke.DOT_STEP_SMALL],
-         LineStroke.DOT_STEP_SMALL);
+         0);
 
    /**
     * Represents a dot style with 3 pixel to draw and then 3 pixel to pass.
@@ -170,6 +171,10 @@
     */
    var joins = [ "miter", "round", "bevel"];
    
+   var workingCanvas = document.createElement('canvas');
+   var workingCtx = workingCanvas.getContext('2d', {alpha : true});
+   workingCtx.imageSmoothingEnabled = false;
+
    /**
     * Holds properties for line drawing styles.
     * 
@@ -233,165 +238,343 @@
    };
    
    /**
-    * Returns the stroke path renderer.
-    * 
-    * @param    {CanvasRenderer} canvasRenderer
-    *           The canvas renderer.
-    * @param    {Number} strokeStyle
-    *           The stroke style id according to the LineStroke enumeration.
-    * @param    {Number} width
-    *           The line width.
-    * @param    {Number[]} strokeColor
-    *           The array of 3 integer values between 0 and 255 inclusive, representing
-    *           a stroke color.
-    * 
-    * @return   The stroke path renderer.
-    */
-   this.getStrokePathRenderer = function(canvasRenderer, strokeStyle, width, strokeColor)
-   {
-      var basicStroke = getLineStroke(strokeStyle, width);
-      
-      switch (strokeStyle)
-      {
-         case LineStrokeEnum.SPECIFIED_WIDTH:
-            return new WidenPathRenderer(canvasRenderer, basicStroke, strokeColor);
-         case LineStrokeEnum.DOTTED:
-         case LineStrokeEnum.DOTTED_SMALL:
-         case LineStrokeEnum.DOTTED_SMALL_THIN:
-         case LineStrokeEnum.DOTTED_LARGE:
-            return new DotsPathRenderer(canvasRenderer, basicStroke, strokeColor);
-         default:
-            return new DefaultPathRenderer(canvasRenderer, strokeColor);
-      }
-   };
-   
-   /**
-    * Returns the stroke path renderer.
-    * 
-    * @param    {CanvasRenderer} canvasRenderer
-    *           The canvas renderer.
-    * @param    {Number[]} strokeColor
-    *           The array of 3 integer values between 0 and 255 inclusive, representing
-    *           a stroke color.
-    * 
-    * @return   The stroke path renderer.
-    */
-   this.getStrokeDefaultPathRenderer = function(canvasRenderer, strokeColor)
-   {
-      return new DefaultPathRenderer(canvasRenderer, strokeColor);
-   }
-   
-   /**
-    * Apply the given stroke style to the JS native canvas renderer.
-    * 
-    * @param    {CanvasRenderingContext2D} context
-    *           The canvas renderer context.
-    * @param    {Number} strokeStyle
-    *           The stroke style id.
-    * @param    {Number} width
-    *           The line width.
-    */
-   this.applyStrokeToCanvas = function(context, strokeStyle, width)
-   {
-      if (context instanceof CanvasRenderingContext2D)
-      {
-         var basicStroke = getLineStroke(strokeStyle, width);
-         context.lineWidth = basicStroke.getWidth();
-         
-         context.lineCap = basicStroke.getCap();
-         
-         context.lineJoin = basicStroke.getJoin();
-         
-         context.miterLimit = basicStroke.getMiterLimit();
-         if (basicStroke.getDash())
-         {
-            context.setLineDash(basicStroke.getDash());
-         }
-         else
-         {
-            context.setLineDash([]);
-         }
-         context.lineDashOffset = basicStroke.getDashPhase();
-      }
-   }
-   
-   /**
-    * Returns the default stroke that is a solid line style with 1 pixel line width.
-    * 
-    * @return   {Number} The default stroke style.
-    */
-   this.getDefaultStrokeStyle = function()
-   {
-      return LineStrokeEnum.DEFAULT;
-   }
-
-   /**
-    * Defines StrokeRenderer class
-    */
-   function StrokeRenderer()
-   {
-   }
-
-   /**
-    * Defines the constructor function
-    */
-   StrokeRenderer.prototype.constructor = StrokeRenderer;
-
-   /**
-    * Prepare the object. This method is used to initialize and to reset the stroke renderer. 
-    */
-   StrokeRenderer.prototype.beginStroke = function()
-   {
-   };
-
-   /**
-    * Apply the stroke to lines given by the absolute coordinates. This method is used to stroke
-    * only vertical and horizontal lines.
-    * 
-    * @param    {Number} x1
-    *           X coordinate of the starting pixel to be drawn.
-    * @param    {Number} y1
-    *           Y coordinate of the starting pixel to be drawn.
-    * @param    {Number} x2
-    *           X coordinate of the ending pixel to be drawn.
-    * @param    {Number} y2
-    *           Y coordinate of the ending pixel to be drawn.
-    */
-   StrokeRenderer.prototype.strokeLine  = function(x1, y1, x2, y2)
-   {
-   };
-   
-   /**
-    * Apply the stroke to the next point given by its coordinates (x, y). This method is used to
-    * stroke sloped and curved lines. 
-    * 
-    * @param    {Number} x
-    *           X coordinate of the point to be drawn.
-    * @param    {Number} y
-    *           Y coordinate of the point to be drawn.
-    */
-   StrokeRenderer.prototype.strokePoint = function(x, y)
-   {
-   };
-   
-   /**
-    * Used to draw dash patterns on lines of pixels.
-    * 
-    * @param    {CanvasRenderer} canvasRenderer
-    *           The canvas renderer.
-    * @param    {Object} basicStroke
-    *           The stroke style object.
-    * @param    {Number[]} strokeColor
-    *           The array of 3 integer values between 0 and 255 inclusive, representing
-    *           a stroke color.
-    */
-   function DotsPathRenderer(canvasRenderer, basicStroke, strokeColor)
-   {
-      var pixel = canvasRenderer.createImageData(1, 1);
-      var pixelData = pixel.data;
-      pixelData[3] = 0xFF;
+    * Defines the creator method of the base StrokeRenderer object.
+    * 
+    * @param    {Object} sharedObject
+    *           The object shared between creators in the inheritance chain.
+    * 
+    * @return   The new instance of StrokeRenderer
+    */
+   function strokeRenderer(sharedObject)
+   {
+      /** This shared container holds the following objects:
+       *  
+       *  var canvasRenderer;
+       *  var basicStroke;
+       *  var strokeColor;
+       *  var colorSpec;
+       *  var penImage;
+       *  var penData;
+       *  var canvas;
+       *  var ctx;
+       *  var screenImage;
+       *  var lineImage;
+       */
+      var me = sharedObject || {};
+      
+      var that = {};
+      
+      /**
+       * Sets the canvas renderer.
+       * 
+       * @param    {CanvasRenderer} canvasRenderer
+       *           The canvas renderer.
+       */
+      that.setCanvasRenderer = function(canvasRenderer)
+      {
+         me.canvasRenderer = canvasRenderer;
+         
+         return that;
+      };
+   
+      /**
+       * Set a current stroke.
+       * 
+       * @param    {Object} stroke
+       *           The stroke style object.
+       */
+      that.setBasicStroke = function(stroke)
+      {
+         me.basicStroke = stroke;
+         me.strokeWidth = stroke.getWidth();
+         
+         return that;
+      };
+   
+      /**
+       * Set a current stroke color.
+       * 
+       * @param    {Number[]} color
+       *           The array of 3 integer values between 0 and 255 inclusive, representing a stroke color.
+       */
+      that.setStrokeColor = function(color)
+      {
+         me.strokeColor = color;
+         
+         assignPenColor();
+         
+         return that;
+      };
+      
+      /**
+       * Sets the image data for the pen.
+       * 
+       * @param    {ImageData} image
+       *           The image data for the pen.
+       */
+      that.setPenImage = function(image)
+      {
+         me.penImage = image;
+         
+         me.penData = image.data;
+         
+         assignPenColor();
+         
+         return that;
+      };
+      
+      /**
+       * Set the current color for the pen.
+       */
+      function assignPenColor()
+      {
+         if (me.penImage && me.strokeColor)
+         {
+            var width = me.penImage.width;
+            var height = me.penImage.height;
+            
+            for (var i = 0; i < 4 * width * height; i += 4)
+            {
+               me.penData[i]     = me.strokeColor[0];
+               me.penData[i + 1] = me.strokeColor[1];
+               me.penData[i + 2] = me.strokeColor[2];
+               me.penData[i + 3] = 255;
+            }
+         }
+      }
+      
+      /**
+       * Sets the working canvas.
+       * 
+       * @param    {Canvas} workingCanvas
+       *           The working canvas.
+       * @param    {CanvasDrawingContext} workingCtx
+       *           The working drawing context.
+       */
+      that.setWorkingCanvas = function(workingCanvas, workingCtx)
+      {
+         me.canvas = workingCanvas;
+         me.ctx = workingCtx;
+         
+         return that;
+      };
+      
+      /**
+       * Set new detached screen image with the same width and height as its working canvas. It 
+       * doesn't check that the new screen image has the width and height as its working canvas.
+       * 
+       * @param    {ImageData} screenImage
+       *           New detached screen image with the same width and height as its working canvas
+       */
+      that.setScreenImage = function(screenImage)
+      {
+         me.screenImage = screenImage;
+         
+         return that;
+      };
+      
+      /**
+       * Prepare the object. This method is used to initialize and to reset the stroke renderer.
+       * 
+       * @param    {Number} rx1
+       *           X coordinate of the top left point of the rectangular drawing area.
+       * @param    {Number} ry1
+       *           Y coordinate of the top left point of the rectangular drawing area.
+       * @param    {Number} rx2
+       *           X coordinate of the right bottom point of the rectangular drawing area.
+       * @param    {Number} ry2
+       *           Y coordinate of the right bottom point of the rectangular drawing area.
+       */
+      that.beginStroke = function(rx1, ry1, rx2, ry2)
+      {
+         if (rx1 != undefined && rx2 != undefined && ry1 != undefined && ry2 != undefined)
+         {
+            me.r = { x1 : rx1,
+                       y1 : ry1,
+                       x2 : rx2,
+                       y2 : ry2 };
+         }
+         else
+         {
+            me.r = undefined;
+         }
+         
+         return that;
+      };
+   
+      /**
+       * Apply the stroke to lines given by the absolute coordinates. This method is used to stroke
+       * only vertical and horizontal lines.
+       * 
+       * @param    {Number} x1
+       *           X coordinate of the starting pixel to be drawn.
+       * @param    {Number} y1
+       *           Y coordinate of the starting pixel to be drawn.
+       * @param    {Number} x2
+       *           X coordinate of the ending pixel to be drawn.
+       * @param    {Number} y2
+       *           Y coordinate of the ending pixel to be drawn.
+       */
+      that.strokeLine  = function(x1, y1, x2, y2)
+      {
+         // Put the line image on the canvas
+         if (me.r)
+         {
+            if (me.screenImage)
+            {
+               var awidth = me.screenImage.width;
+               var aheight = me.screenImage.height;
+               var limit = (y2 * awidth + x2) * 4;
+               var x = x1;
+               var y = y1;
+               var dp = awidth * 4;
+               
+               // precondition: y2 should be greater or equal than y1.
+               for (var p = (y1 * awidth + x1) * 4; p <= limit; )
+               {
+                  strokePoint(x, y);
+                  
+                  if (x1 == x2)
+                  {
+                     y++;
+                     p += dp;
+                  }
+                  else
+                  {
+                     x++;
+                     p += 4;
+                  }
+               }
+            }
+            else if (me.lineImage)
+            {
+               var d = me.stokeWidth >> 1;
+               me.ctx.putImageData(me.lineImage, x1 - d - me.r.x1, y1 - d - me.r.y1);
+            }
+         }
+         else
+         {
+            me.ctx.putImageData(me.lineImage, 0, 0);
+            var d = me.stokeWidth >> 1;
+            /*
+            me.canvasRenderer.offscreenCtx.save();
+            me.canvasRenderer.offscreenCtx.strokeStyle = "red";
+            me.canvasRenderer.offscreenCtx.strokeWidth = 1;
+            me.canvasRenderer.offscreenCtx.beginPath();
+            me.canvasRenderer.offscreenCtx.rect(x1 - d, y1 - d, me.lineWidth, me.lineHeight);
+            me.canvasRenderer.offscreenCtx.stroke();
+            me.canvasRenderer.offscreenCtx.restore();*/
+
+            me.canvasRenderer.drawCanvas(me.canvas, x1 - d, y1 - d, me.lineWidth, me.lineHeight);
+         }
+         
+         return that;
+      };
+      
+      /**
+       * Apply the stroke to the next point given by its coordinates (x, y). This method is used to
+       * stroke sloped and curved lines.
+       * 
+       * @param    {Number} x
+       *           X coordinate of the point to be drawn.
+       * @param    {Number} y
+       *           Y coordinate of the point to be drawn.
+       */
+      function strokePoint(x, y)
+      {
+         var d = me.strokeWidth >> 1;
+         
+         if (me.screenImage)
+         {
+            var awidth = me.screenImage.width;
+            var p = 4 * (x - me.r.x1 + d) + 4 * (y - me.r.y1 + d) * awidth;
+            var data = me.penImage.data;
+            
+            if (me.strokeWidth == 1)
+            {
+               me.screenImage.data.set(data, p);
+            }
+            else
+            {
+               var aPenWidth = me.penImage.width;
+               var limit = me.strokeWidth - d;
+               for (var dx = -d; dx < limit; dx++)
+               {
+                  for (var dy = -d; dy < limit; dy++)
+                  {
+                     var q  = 4 * (dx + d) + 4 * (dy + d) * aPenWidth;
+                     var q1 = p + 4 * dx + 4 * dy * awidth;
+                     if ((q1 >= 0) && (q1 < me.screenImage.data.length))
+                     {
+                        me.screenImage.data[q1] = data[q];
+                        me.screenImage.data[q1 + 1] = data[q + 1];
+                        me.screenImage.data[q1 + 2] = data[q + 2];
+                        me.screenImage.data[q1 + 3] = data[q + 3];
+                     }
+                  }
+               }
+            }
+         }
+         else if (me.r)
+         {
+            me.ctx.putImageData(me.penImage, x - me.r.x1 /*+ d*/, y - me.r.y1 /*+ d*/);
+         }
+         else
+         {
+            me.canvasRenderer.putImageData(me.penImage, x - d, y - d);
+         }
+         
+         return that;
+      };
+      
+      that.strokePoint = strokePoint;
+      
+      /**
+       * Close the current stroke operation. This method is used to draw the result image by canvas renderer.
+       */
+      that.endStroke = function()
+      {
+         if (me.screenImage)
+         {
+            me.ctx.putImageData(me.screenImage, 0, 0);
+         }
+         if (me.r)
+         {
+            var d = me.strokeWidth >> 1;
+            /*
+            me.canvasRenderer.offscreenCtx.save();
+            me.canvasRenderer.offscreenCtx.strokeStyle = "blue";
+            me.canvasRenderer.offscreenCtx.strokeWidth = 1;
+            me.canvasRenderer.offscreenCtx.beginPath();
+            me.canvasRenderer.offscreenCtx.rect(me.r.x1 - d, me.r.y1 - d,
+                                           me.r.x2 - me.r.x1 + me.strokeWidth,
+                                           me.r.y2 - me.r.y1 + me.strokeWidth);
+            me.canvasRenderer.offscreenCtx.stroke();
+            me.canvasRenderer.offscreenCtx.restore();*/
+            me.canvasRenderer.drawCanvas(me.canvas, me.r.x1 /*- d*/, me.r.y1 /*- d*/,
+                                         me.r.x2 - me.r.x1 + me.strokeWidth,
+                                         me.r.y2 - me.r.y1 + me.strokeWidth);
+         }
+         
+         return that;
+      };
+      
+      return that;
+   }
+   
+   /**
+    * Defines the creator method of the DotsPathRenderer object. Used to draw lines with dash patterns.
+    */
+   function dotsPathRenderer()
+   {
+      var me = {};
+      var that = strokeRenderer(me);
+      var super_beginStroke = that["beginStroke"];
+      var super_strokeLine = that["strokeLine"];
+      var super_strokePoint = that["strokePoint"];
+      
       var state = {};
-
+      
       /**
        * Normalizes a dash offset distance according to the given dash pattern.
        * A normalized dash offset distance is a distance that is cut the corresponding segment
@@ -429,14 +612,11 @@
       /**
        * Prepares the given stroke to be applied to the line of pixels called a path.
        */
-      this.beginStroke = function()
+      that.beginStroke = function(rx1, ry1, rx2, ry2)
       {
-         var dash = basicStroke.getDash();
-         if (!dash || dash.length == 0)
-         {
-            return;
-         }
-         var dashOffset = basicStroke.getDashPhase();
+         super_beginStroke(rx1, ry1, rx2, ry2);
+         var dash = me.basicStroke.getDash();
+         var dashOffset = me.basicStroke.getDashPhase();
          var len = dash.length;
          
          var patternObj = normalize(dash, dashOffset);
@@ -451,8 +631,10 @@
          state.dashOn = dashOn;
          state.idx    = idx;
          state.rest   = rest;
+         
+         return that;
       }
-      
+
       /**
        * Apply the stroke to vertical or horizontal lines given by the absolute coordinates that
        * satisfy x1 <= x2 and y1 <= y2.
@@ -466,7 +648,7 @@
        * @param    {Number} y2
        *           Y coordinate of the ending pixel to be drawn.
        */
-      this.strokeLine = function(x1, y1, x2, y2)
+      that.strokeLine = function(x1, y1, x2, y2)
       {
          var rest   = state.rest;
          var idx    = state.idx;
@@ -475,43 +657,72 @@
          var dash   = state.dash;
          // precondition: dx should be greater or equal than zero.
          var dx = x2 - x1;
-         var x = x1;
-         var y = y1;
-         // precondition: y2 should be greater or equal than y1.
-         while(x <= x2 && y <= y2)
-         {
-            if (rest < 1)
-            {
-               idx    = (idx + 1) % len;
-               rest   = state.dash[idx];
-               dashOn = !dashOn;
-            }
-            rest -= 1;
-            
-            if (dashOn)
-            {
-               // fill a pixel and put it on the canvas.
-               pixelData[0] = strokeColor[0];
-               pixelData[1] = strokeColor[1];
-               pixelData[2] = strokeColor[2];
-               canvasRenderer.putImageData(pixel, x, y);
-            }
-            // vertical line: increase Y-coordinate
-            if (dx === 0)
-            {
-               y = y + 1;
-            }
-            else // horizontal line: increase X-coordinate
-            {
-               x = x + 1;
-            }
-         }
+         
+         me.lineWidth  = x2 - x1 + 1;
+         me.lineHeight = y2 - y1 + 1;
+         
+         if (!me.r)
+         {
+            me.canvas.width  = me.lineWidth;
+            me.canvas.height = me.lineHeight;
+         }
+         me.lineImage = me.screenImage || me.ctx.createImageData(me.lineWidth, me.lineHeight);
+         var data = me.lineImage.data;
+         var awidth = me.lineImage.width;
+         var aheight = me.lineImage.height;
+         var length = 4 * awidth * aheight;
+         
+         if (!me.screenImage)
+         {
+            var x = 0;
+            var y = 0;
+            // precondition: y2 should be greater or equal than y1.
+            for (var p = 0; p < length; )
+            {
+               if (rest < 1)
+               {
+                  idx    = (idx + 1) % len;
+                  rest   = state.dash[idx];
+                  dashOn = !dashOn;
+               }
+               rest -= 1;
+               
+               if (dashOn)
+               {
+                  // fill a pixel and put it on the canvas.
+                  data[p]     = me.strokeColor[0];
+                  data[p + 1] = me.strokeColor[1];
+                  data[p + 2] = me.strokeColor[2];
+                  data[p + 3] = 255;
+               }
+               
+               x++;
+               // p = (y * awidth + x) * 4
+               // p1 - p0 = [(y1 - y0) * awidth + (x1 - x0)] * 4 = 4 or 4 * (awidth - width) + 4 
+               if (x == me.lineWidth)
+               {
+                  y++;
+                  x = 0;
+                  p += ((awidth - me.lineWidth + 1) * 4);
+               }
+               else
+               {
+                  p += 4; 
+               }
+            }
+   
+            // Put the line image on the canvas
+            super_strokeLine(x1, y1, x2, y2);
+         }
+         
          // save the dash pattern state in order to continue this dash pattern for next drawings 
          state.dashOn = dashOn;
          state.rest   = rest;
          state.idx    = idx;
+         
+         return that;
       }
-      
+
       /**
        * Apply the stroke to the next point given by its coordinates (x, y).
        * 
@@ -520,7 +731,7 @@
        * @param    {Number} y
        *           Y coordinate of the point to be drawn.
        */
-      this.strokePoint = function(x, y)
+      that.strokePoint = function(x, y)
       {
          var rest   = state.rest;
          var idx    = state.idx;
@@ -535,62 +746,30 @@
          rest -= 1;
          if (dashOn)
          {
-            // fill a pixel and put it on the canvas.
-            pixelData[0] = strokeColor[0];
-            pixelData[1] = strokeColor[1];
-            pixelData[2] = strokeColor[2];
-            canvasRenderer.putImageData(pixel, x, y);
+            super_strokePoint(x, y);
          }
          // save the dash pattern state in order to continue this dash pattern for next drawings 
          state.dashOn = dashOn;
          state.rest   = rest;
          state.idx    = idx;
+         
+         return that;
       }
       
+      return that;
    }
    
    /**
-    * DotsPathRenderer implements StrokeRenderer methods
+    * Defines the creator method of the WidenPathRenderer object. Used to draw wide solid lines having 
+    * more than a one pixel width.
     */
-   DotsPathRenderer.prototype = Object.create(StrokeRenderer.prototype);
+   function widenPathRenderer()
+   {
+      var me = {};
+      var that = strokeRenderer(me);
+      var super_strokeLine  = that["strokeLine"];
+      var super_strokePoint = that["strokePoint"];
 
-   /**
-    * Defines the constructor function
-    */
-   DotsPathRenderer.prototype.constructor = DotsPathRenderer;
-   
-   /**
-    * Used to widen lines of pixels.
-    * 
-    * @param    {CanvasRenderer} canvasRenderer
-    *           The canvas renderer.
-    * @param    {Object} basicStroke
-    *           The stroke style object.
-    * @param    {Number[]} strokeColor
-    *           The array of 3 integer values between 0 and 255 inclusive, representing
-    *           a stroke color.
-    */
-   function WidenPathRenderer(canvasRenderer, basicStroke, strokeColor)
-   {
-      var width = basicStroke.getWidth();
-      var image = canvasRenderer.createImageData(width, width);
-      var imageData = image.data;
-      
-      for (var i = 0; i < 4 * width * width; i += 4)
-      {
-         imageData[i] = strokeColor[0];
-         imageData[i + 1] = strokeColor[1];
-         imageData[i + 2] = strokeColor[2];
-         imageData[i + 3] = 0xFF;
-      }
-      
-      /**
-       * Prepares the given stroke to be applied to the line of pixels called a path.
-       */
-      this.beginStroke = function()
-      {
-      }
-      
       /**
        * Apply the stroke to vertical or horizontal lines given by the absolute coordinates that
        * satisfy x1 <= x2 and y1 <= y2.
@@ -604,83 +783,53 @@
        * @param    {Number} y2
        *           Y coordinate of the ending pixel to be drawn.
        */
-      this.strokeLine = function(x1, y1, x2, y2)
+      that.strokeLine = function(x1, y1, x2, y2)
       {
          // calculate the minimal rectangle width and height that covers and fills
          //a line that should be widen to have the given width
-         var lineWidth  = x2 - x1 + width;
-         var lineHeight = y2 - y1 + width;
-         var x0 = x1 - (width >> 1);
-         var y0 = y1 - (width >> 1);
+         me.lineWidth  = x2 - x1 + me.strokeWidth;
+         me.lineHeight = y2 - y1 + me.strokeWidth;
+         
+         if (!me.r)
+         {
+            me.canvas.width = me.lineWidth;
+            me.canvas.height = me.lineHeight;
+         }
+         
          // create an image to draw the widen line
-         var screenImage = canvasRenderer.createImageData(lineWidth, lineHeight);
-         var data = screenImage.data;
-         var length = 4 * lineWidth * lineHeight;
+         me.lineImage =  me.screenImage || me.ctx.createImageData(me.lineWidth, me.lineHeight);
+         var data = me.lineImage.data;
+         var length = 4 * me.lineWidth * me.lineHeight;
          
-         for (var i = 0; i < length; i += 4)
+         if (!me.screenImage)
          {
-            data[i]     = strokeColor[0];
-            data[i + 1] = strokeColor[1];
-            data[i + 2] = strokeColor[2];
-            data[i + 3] = 255;
+            for (var i = 0; i < length; i += 4)
+            {
+               data[i]     = me.strokeColor[0];
+               data[i + 1] = me.strokeColor[1];
+               data[i + 2] = me.strokeColor[2];
+               data[i + 3] = 255;
+            }
          }
-         canvasRenderer.putImageData(screenImage, x0, y0);
+         
+         // Put the line image on the canvas
+         super_strokeLine(x1, y1, x2, y2);
+         
+         return that;
       }
       
-      /**
-       * Apply the stroke to the next point given by its coordinates (x, y).
-       * 
-       * @param    {Number} x
-       *           X coordinate of the point to be drawn.
-       * @param    {Number} y
-       *           Y coordinate of the point to be drawn.
-       */
-      this.strokePoint = function(x, y)
-      {
-         canvasRenderer.putImageData(image, x - (width >> 1), y - (width >> 1));
-      }
-
+      return that;
    }
-   
-   /**
-    * WidenPathRenderer implements StrokeRenderer methods
-    */
-   WidenPathRenderer.prototype = Object.create(StrokeRenderer.prototype);
-
-   /**
-    * Defines the constructor function
-    */
-   WidenPathRenderer.prototype.constructor = WidenPathRenderer;
-
-   /**
-    * The default lines renderer.
-    * 
-    * @param    {CanvasRenderer} canvasRenderer
-    *           The canvas renderer.
-    * @param    {Number[]} strokeColor
-    *           The array of 3 integer values between 0 and 255 inclusive, representing
-    *           a stroke color.
-    */
-   function DefaultPathRenderer(canvasRenderer, strokeColor)
+
+   /**
+    * Defines the creator method of the DefaultPathRenderer object to draw solid lines having a one pixel width.
+    */
+   function defaultPathRenderer()
    {
-      var width = defaultStroke.getWidth();
-      var image = canvasRenderer.createImageData(width, width);
-      var imageData = image.data;
-      
-      for (var i = 0; i < 4 * width * width; i += 4)
-      {
-         imageData[i]     = strokeColor[0];
-         imageData[i + 1] = strokeColor[1];
-         imageData[i + 2] = strokeColor[2];
-         imageData[i + 3] = 255;
-      }
-      
-      /**
-       * Prepares the given stroke to be applied to the line of pixels called a path.
-       */
-      this.beginStroke = function()
-      {
-      }
+      var me = {};
+      var that = strokeRenderer(me);
+      
+      var super_strokeLine = that["strokeLine"];
       
       /**
        * Apply the stroke to vertical or horizontal lines given by the absolute coordinates that
@@ -695,36 +844,47 @@
        * @param    {Number} y2
        *           Y coordinate of the ending pixel to be drawn.
        */
-      this.strokeLine = function(x1, y1, x2, y2)
+      that.strokeLine = function(x1, y1, x2, y2)
       {
          // The default line width is 1 pixel.
-         // Calculate the line with and height to draw a line as an image
-         var lineWidth  = x2 - x1 + 1;
-         var lineHeight = y2 - y1 + 1;
+         // Calculate the line width and height to draw a line as an image
+         me.lineWidth  = x2 - x1 + 1;
+         me.lineHeight = y2 - y1 + 1;
+         
+         if (!me.r)
+         {
+            me.canvas.width  = me.lineWidth;
+            me.canvas.height = me.lineHeight;
+         }
          // Create a line image
-         var screenImage = canvasRenderer.createImageData(lineWidth, lineHeight);
-         var data = screenImage.data;
-         var length = 4 * lineWidth * lineHeight;
-
-         // Fill a line image with the given stroke color
-         data[0] = strokeColor[0];
-         data[1] = strokeColor[1];
-         data[2] = strokeColor[2];
-         data[3] = 255;
-
-         var pos = 4;
-         var seqLen = 4;
-         while(pos < length)
+         me.lineImage = me.screenImage || me.ctx.createImageData(me.lineWidth, me.lineHeight);
+         var data = me.lineImage.data;
+         var length = 4 * me.lineWidth * me.lineHeight;
+
+         if (!me.screenImage)
          {
-            data.copyWithin(pos, 0, seqLen);
-            // increment position by the length of the current segment
-            pos += seqLen;
-            // double the length of the next segment
-            seqLen <<= 1;
+            // Fill a line image with the given stroke color
+            data[0] = me.strokeColor[0];
+            data[1] = me.strokeColor[1];
+            data[2] = me.strokeColor[2];
+            data[3] = 255;
+   
+            var pos = 4;
+            var seqLen = 4;
+            while(pos < length)
+            {
+               data.copyWithin(pos, 0, seqLen);
+               // increment position by the length of the current segment
+               pos += seqLen;
+               // double the length of the next segment
+               seqLen <<= 1;
+            }
          }
-
+         
          // Put the line image on the canvas
-         canvasRenderer.putImageData(screenImage, x1, y1);
+         super_strokeLine(x1, y1, x2, y2);
+         
+         return that;
       }
       
       /**
@@ -748,81 +908,184 @@
        * @param    {Number} y2
        *           Y coordinate of the ending pixel to be drawn.
        */
-      this.xorLine = function(x1, y1, x2, y2)
+      that.xorLine = function(x1, y1, x2, y2)
       {
          // The default line width is 1 pixel.
          // Calculate the line with and height to draw a line as an image
          var lineWidth  = x2 - x1 + 1;
          var lineHeight = y2 - y1 + 1;
          // Get current image data from screen
-         var screenImage = canvasRenderer.screenCtx.getImageData(x1, y1, lineWidth, lineHeight);
+         var screenImage = me.canvasRenderer.screenCtx.getImageData(x1, y1, lineWidth, lineHeight);
          var data = screenImage.data;
          var length = 4 * lineWidth * lineHeight;
          // Fill a line image with the given stroke color
          for (var i = 0; i < length; i += 4)
          {
-            if (data[i] != canvasRenderer.iBeamColor[0])
-            {
-               if (data[i] == strokeColor[0] || data[i + 3] == 0)
-               {
-                  data[i] = canvasRenderer.iBeamColor[0];
-               }
-               else
-               {
-                  data[i] = data[i] ^ strokeColor[0];
-               }
-            }
-            if (data[i + 1] != canvasRenderer.iBeamColor[1])
-            {
-               if (data[i + 1] == strokeColor[1] || data[i + 3] == 0)
-               {
-                  data[i + 1] = canvasRenderer.iBeamColor[1];
-               }
-               else
-               {
-                  data[i + 1] = data[i + 1] ^ strokeColor[1];
-               }
-            }
-            if (data[i + 2] != canvasRenderer.iBeamColor[2])
-            {
-               if (data[i + 2] == strokeColor[2] || data[i + 3] == 0)
-               {
-                  data[i + 2] = canvasRenderer.iBeamColor[2];
-               }
-               else
-               {
-                  data[i + 2] = data[i + 2] ^ strokeColor[2];
+            if (data[i] != me.canvasRenderer.iBeamColor[0])
+            {
+               if (data[i] == me.strokeColor[0] || data[i + 3] == 0)
+               {
+                  data[i] = me.canvasRenderer.iBeamColor[0];
+               }
+               else
+               {
+                  data[i] = data[i] ^ me.strokeColor[0];
+               }
+            }
+            if (data[i + 1] != me.canvasRenderer.iBeamColor[1])
+            {
+               if (data[i + 1] == me.strokeColor[1] || data[i + 3] == 0)
+               {
+                  data[i + 1] = me.canvasRenderer.iBeamColor[1];
+               }
+               else
+               {
+                  data[i + 1] = data[i + 1] ^ me.strokeColor[1];
+               }
+            }
+            if (data[i + 2] != me.canvasRenderer.iBeamColor[2])
+            {
+               if (data[i + 2] == me.strokeColor[2] || data[i + 3] == 0)
+               {
+                  data[i + 2] = me.canvasRenderer.iBeamColor[2];
+               }
+               else
+               {
+                  data[i + 2] = data[i + 2] ^ me.strokeColor[2];
                }
             }
             data[i + 3] = 255;
          }
          // Put the line image on the canvas
-         canvasRenderer.putImageData(screenImage, x1, y1);
-      }
-      
-      /**
-       * Apply the stroke to the next point given by its coordinates (x, y).
-       * 
-       * @param    {Number} x
-       *           X coordinate of the point to be drawn.
-       * @param    {Number} y
-       *           Y coordinate of the point to be drawn.
-       */
-      this.strokePoint = function(x, y)
-      {
-         canvasRenderer.putImageData(image, x, y);
-      }
-
-   }
-
-   /**
-    * DefaultPathRenderer implements StrokeRenderer methods
-    */
-   DefaultPathRenderer.prototype = Object.create(StrokeRenderer.prototype);
-
-   /**
-    * Defines the constructor function
-    */
-   DefaultPathRenderer.prototype.constructor = DefaultPathRenderer;
-
+         me.canvasRenderer.putImageData(screenImage, x1, y1);
+         
+         return that;
+      }
+      
+      return that;
+   }
+   
+   /**
+    * The base renderer that is used to draw solid lines of 1 pixel width.
+    */
+   var defaultPathRenderer = defaultPathRenderer();
+   
+   /**
+    * The dots renderer that is used to draw dots styled lines.
+    */
+   var dotsPathRenderer = dotsPathRenderer();
+   
+   /**
+    * The widen renderer that is used to draw solid lines of the specified width.
+    */
+   var widenPathRenderer = widenPathRenderer();
+   
+   /**
+    * Returns the stroke path renderer.
+    * 
+    * @param    {CanvasRenderer} canvasRenderer
+    *           The canvas renderer.
+    * @param    {Number} strokeStyle
+    *           The stroke style id according to the LineStroke enumeration.
+    * @param    {Number} width
+    *           The line width.
+    * @param    {Number[]} strokeColor
+    *           The array of 3 integer values between 0 and 255 inclusive, representing
+    *           a stroke color.
+    * 
+    * @return   The stroke path renderer.
+    */
+   this.getStrokePathRenderer = function(canvasRenderer, strokeStyle, width, strokeColor)
+   {
+      var basicStroke = getLineStroke(strokeStyle, width);
+      
+      var renderer;
+      
+      switch (strokeStyle)
+      {
+         case LineStrokeEnum.SPECIFIED_WIDTH:
+            renderer = widenPathRenderer;
+            break;
+         case LineStrokeEnum.DOTTED:
+         case LineStrokeEnum.DOTTED_SMALL:
+         case LineStrokeEnum.DOTTED_SMALL_THIN:
+         case LineStrokeEnum.DOTTED_LARGE:
+            renderer = dotsPathRenderer;
+            break;
+         default:
+            renderer = defaultPathRenderer;
+      }
+      
+      return renderer.setBasicStroke(basicStroke)
+              .setCanvasRenderer(canvasRenderer)
+              .setStrokeColor(strokeColor)
+              .setPenImage(canvasRenderer.createImageData(basicStroke.getWidth(), basicStroke.getWidth()))
+              .setWorkingCanvas(workingCanvas, workingCtx)
+              .setScreenImage(undefined);
+   };
+   
+   /**
+    * Returns the stroke path renderer.
+    * 
+    * @param    {CanvasRenderer} canvasRenderer
+    *           The canvas renderer.
+    * @param    {Number[]} strokeColor
+    *           The array of 3 integer values between 0 and 255 inclusive, representing
+    *           a stroke color.
+    * 
+    * @return   The stroke path renderer.
+    */
+   this.getStrokeDefaultPathRenderer = function(canvasRenderer, strokeColor)
+   {
+      return defaultPathRenderer.setBasicStroke(defaultStroke)
+            .setCanvasRenderer(canvasRenderer)
+            .setStrokeColor(strokeColor)
+            .setPenImage(canvasRenderer.createImageData(defaultStroke.getWidth(), defaultStroke.getWidth()))
+            .setWorkingCanvas(workingCanvas, workingCtx)
+            .setScreenImage(undefined);
+   }
+   
+   /**
+    * Apply the given stroke style to the JS native canvas renderer.
+    * 
+    * @param    {CanvasRenderingContext2D} context
+    *           The canvas renderer context.
+    * @param    {Number} strokeStyle
+    *           The stroke style id.
+    * @param    {Number} width
+    *           The line width.
+    */
+   this.applyStrokeToCanvas = function(context, strokeStyle, width)
+   {
+      if (context instanceof CanvasRenderingContext2D)
+      {
+         var basicStroke = getLineStroke(strokeStyle, width);
+         context.lineWidth = basicStroke.getWidth();
+         
+         context.lineCap = basicStroke.getCap();
+         
+         context.lineJoin = basicStroke.getJoin();
+         
+         context.miterLimit = basicStroke.getMiterLimit();
+         if (basicStroke.getDash())
+         {
+            context.setLineDash(basicStroke.getDash());
+         }
+         else
+         {
+            context.setLineDash([]);
+         }
+         context.lineDashOffset = basicStroke.getDashPhase();
+      }
+   }
+   
+   /**
+    * Returns the default stroke that is a solid line style with 1 pixel line width.
+    * 
+    * @return   {Number} The default stroke style.
+    */
+   this.getDefaultStrokeStyle = function()
+   {
+      return LineStrokeEnum.DEFAULT;
+   }
 }

