Project

General

Profile

performance_issue_4.txt

Sergey Ivanovskiy, 02/17/2016 04:43 PM

Download (29.3 KB)

 
1
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/res/p2j.clipboard.js'
2
--- src/com/goldencode/p2j/ui/client/driver/web/res/p2j.clipboard.js	2015-10-14 16:32:09 +0000
3
+++ src/com/goldencode/p2j/ui/client/driver/web/res/p2j.clipboard.js	2016-02-17 21:22:49 +0000
4
@@ -84,7 +84,8 @@
5
       {
6
          // replace line ends in order to be handled properly on the thin client
7
          // as if "Enter" was pressed
8
-         p2j.socket.sendStringBinaryMessage(0x03, text.replace(/\n/g,"\r")); 
9
+//         p2j.socket.sendStringBinaryMessage(0x03, text.replace(/\n/g,"\r")); 
10
+         p2j.socket.sendStringBinaryMessage(0x03, text); 
11
       }
12
       
13
       ctrlv = false;
14

    
15
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js'
16
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js	2016-02-17 20:45:29 +0000
17
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js	2016-02-17 21:22:49 +0000
18
@@ -24,6 +24,7 @@
19
 **                  getImageData implementation.
20
 **     CA  20160129 Removed the "ctx" parameter from the CanvasRenderer APIs.  Added a global 
21
 **                  cache where widget states are saved.
22
+**     SBI 20160213 Reduced putImageData invocations for horizontal and vertical lines.
23
 */
24
 
25
 "use strict";
26
@@ -92,6 +93,9 @@
27
    /** True value indicates XOR composite operation will be applied. */
28
    this.compositeModeOn = false;
29
    
30
+   /** The screen capture used by drawing primitives */
31
+   this.screenCapture = this.ctx.getImageData(0, 0, 1, 1);
32
+   
33
    // force all drawing to be inside pixel "cells" instead of "stradling" between two cells
34
    // which is the default; this eliminates much of the worst of the anti-aliasing and
35
    // positioning problems inherent in canvas operations; this will also save off the
36
@@ -577,17 +581,11 @@
37
  *           X coordinate of the ending pixel to be drawn.
38
  * @param    {Number} y2
39
  *           Y coordinate of the ending pixel to be drawn.
40
- * @param    {Number[]} color
41
+ * @param    {StrokeRenderer} strokeRenderer
42
  *           Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
43
- * 
44
- * @return   {Array} path
45
- *           The {x:.,y:.} point per a pixel array that represents the drawing line segment.
46
  */
47
-CanvasRenderer.prototype.drawLineSegment = function(x1, y1, x2, y2, color)
48
+CanvasRenderer.prototype.drawLineSegment = function(x1, y1, x2, y2, strokeRenderer)
49
 {
50
-   // holds the line pixels to draw
51
-   var path = [];
52
-
53
    x1 = x1 + this.origin.x;
54
    x2 = x2 + this.origin.x;
55
    
56
@@ -598,7 +596,7 @@
57
    var d = this.cutLine(x1, y1, x2, y2);
58
    if (d === null)
59
    {
60
-      return path;
61
+      return;
62
    }
63
    x1 = d[0];
64
    y1 = d[1];
65
@@ -608,6 +606,38 @@
66
    var dx = Math.abs(x2 - x1);
67
    var dy = Math.abs(y2 - y1);
68
    
69
+   // vertical and horizontal lines are handled by the current stroke renderer (optimization)
70
+   if (dx === 0 || dy === 0)
71
+   {
72
+      strokeRenderer.strokeLine(x1, y1, x2, y2);
73
+   }
74
+   else
75
+   {
76
+      this.drawSlopedLineSegment(x1, y1, x2, y2, strokeRenderer);
77
+   }
78
+};
79
+
80
+/**
81
+ * Draw a sloped line in the given color from (x1, y1) to (x2, y2) inclusive, using direct drawing.
82
+ * <p>
83
+ * This is an implementation of the well known 50+ year old Bresenham algorithm.
84
+ *
85
+ * @param    {Number} x1
86
+ *           X coordinate of the starting pixel to be drawn.
87
+ * @param    {Number} y1
88
+ *           Y coordinate of the starting pixel to be drawn.
89
+ * @param    {Number} x2
90
+ *           X coordinate of the ending pixel to be drawn.
91
+ * @param    {Number} y2
92
+ *           Y coordinate of the ending pixel to be drawn.
93
+ * @param    {StrokeRenderer} strokeRenderer
94
+ *           The current stroke renderer.
95
+ */
96
+CanvasRenderer.prototype.drawSlopedLineSegment = function(x1, y1, x2, y2, strokeRenderer)
97
+{
98
+   var dx = Math.abs(x2 - x1);
99
+   var dy = Math.abs(y2 - y1);
100
+
101
    var xIncr = x1 < x2 ? 1 : -1;
102
    var yIncr = y1 < y2 ? 1 : -1;
103
    
104
@@ -618,17 +648,11 @@
105
    
106
    var x = x1;
107
    var y = y1;
108
-   
109
    var tooMany = 0;
110
-   var directStroke = this.strokesManager.isDirectDrawingStrokeStyle(this.strokeStyleId);
111
    
112
    while (true)
113
    {
114
-      if (directStroke)
115
-      {
116
-         this.drawPixel(x, y, color);
117
-      }
118
-      path.push({x : x, y : y});
119
+      strokeRenderer.strokePoint(x, y);
120
       
121
       tooMany++;
122
       
123
@@ -640,7 +664,7 @@
124
       {
125
          if (tooMany > 10000)
126
          {
127
-            this.logger.logFormatted("Bresenham is out of control for x1 = %d, y1 = %d,"
128
+            renderer.logger.logFormatted("Bresenham is out of control for x1 = %d, y1 = %d,"
129
                      + " x2 = %d, y2 = %d and current x = %d, y = %d!",[x1, y1, x2, y2, x, y]);
130
             console.trace();
131
             break;
132
@@ -661,11 +685,10 @@
133
          y   += yIncr;
134
       }
135
    }
136
-   
137
-   return path;
138
-};
139
+}
140
 
141
 /**
142
+ * 
143
  * Draw a line in the given color from (x1, y1) to (x2, y2) inclusive, using direct drawing and
144
  * add its pixels path to the end of the provided pixels path.
145
  * <p>
146
@@ -681,22 +704,17 @@
147
  *           Y coordinate of the ending pixel to be drawn.
148
  * @param    {Number[]} color
149
  *           Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
150
- * @param    {Array} path
151
- *           The provided holder of {x:.,y:.} points, the target drawing as a set of sequential
152
- *           line points will be added at the end of the provided path.
153
- * @return   {Array}
154
- *           The {x:.,y:.} point per a pixel array that represents the drawing line segment.
155
  */
156
-CanvasRenderer.prototype.drawLine = function(x1, y1, x2, y2, color, path)
157
+CanvasRenderer.prototype.drawLine = function(x1, y1, x2, y2, color)
158
 {
159
-   var segment = this.drawLineSegment(x1, y1, x2, y2, color);
160
-   Array.prototype.push.apply(path, segment);
161
-   return segment;
162
+   var strokeRenderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
163
+         this.strokeWidth, color);
164
+   strokeRenderer.beginStroke();
165
+   this.drawLineSegment(x1, y1, x2, y2, strokeRenderer);
166
 }
167
 
168
 /**
169
- * Stroke a line in the given color from (x1, y1) to (x2, y2) inclusive, using direct drawing and
170
- * add its pixels path to the end of the provided pixels path.
171
+ * Stroke a line in the given color from (x1, y1) to (x2, y2) inclusive.
172
  * <p>
173
  * This is an implementation of the well known 50+ year old Bresenham algorithm.
174
  *
175
@@ -710,18 +728,13 @@
176
  *           Y coordinate of the ending pixel to be drawn.
177
  * @param    {Number[]} color
178
  *           Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
179
- * @param    {Array} path
180
- *           The provided holder of {x:.,y:.} points, the target drawing as a set of sequential
181
- *           line points will be added at the end of the provided path.
182
  */
183
 CanvasRenderer.prototype.strokeLineSegment = function(x1, y1, x2, y2, color)
184
 {
185
-   var path = this.drawLineSegment(x1, y1, x2, y2, color);
186
-   this.strokesManager.applyStrokeToPath(this,
187
-         this.strokeStyleId,
188
-         this.strokeWidth,
189
-         color,
190
-         path);
191
+   var strokeRenderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
192
+         this.strokeWidth, color);
193
+   strokeRenderer.beginStroke();
194
+   this.drawLineSegment(x1, y1, x2, y2, strokeRenderer);
195
 }
196
 
197
 /**
198
@@ -741,15 +754,11 @@
199
  *           This will be used for the border lines and when in fill mode, also the interior.
200
  * @param    {Boolean} fill
201
  *           <code>true</code> to fill the drawn rectangle with the given color.
202
- * 
203
- * @return   {Array} path
204
- *           The {x:.,y:.} point per a pixel array that represents the rectangle outerline.
205
  */
206
 CanvasRenderer.prototype.drawRect = function(x, y, width, height, color, fill)
207
 {
208
    // filled rectangles draw 1 pixel smaller in 2 dimensions than stroked rectangles
209
    var inset = 0;
210
-   var path  = [];
211
    // use vector operations for the interior of the rectangle
212
    if (fill)
213
    {
214
@@ -761,12 +770,13 @@
215
    
216
    // now overdraw the stroked portion to eliminate anti-aliasing, we draw in a
217
    // clockwise direction (since we are not using paths, this is not strictly necessary)
218
-   this.drawLine(x, y, x + width - inset, y, color, path);
219
-   this.drawLine(x + width - inset, y + 1, x + width - inset, y + height - inset, color, path);
220
-   this.drawLine(x + width - 1 - inset, y + height - inset, x + 1, y + height - inset, color, path);
221
-   this.drawLine(x, y + height - inset, x, y + 1, color, path);// close the path
222
-   
223
-   return path;
224
+   var renderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
225
+         this.strokeWidth, color);
226
+   renderer.beginStroke();
227
+   this.drawLineSegment(x, y, x + width - inset, y, renderer);
228
+   this.drawLineSegment(x + width - inset, y + 1, x + width - inset, y + height - inset, renderer);
229
+   this.drawLineSegment(x + width - 1 - inset, y + height - inset, x + 1, y + height - inset, renderer);
230
+   this.drawLineSegment(x, y + height - inset, x, y + 1, renderer);// close the path
231
 };
232
 
233
 /**
234
@@ -791,7 +801,6 @@
235
 {
236
    // filled rectangles draw 1 pixel smaller in 2 dimensions than stroked rectangles
237
    var inset = 0;
238
-   var path  = [];
239
    // use vector operations for the interior of the rectangle
240
    if (fill)
241
    {
242
@@ -803,16 +812,16 @@
243
    
244
    // now overdraw the stroked portion to eliminate anti-aliasing, we draw in a
245
    // clockwise direction (since we are not using paths, this is not strictly necessary)
246
-   this.drawLine(x, y, x + width - inset, y, color, path);
247
-   this.drawLine(x + width - inset, y + 1, x + width - inset, y + height - inset, color, path);
248
-   this.drawLine(x + width - 1 - inset, y + height - inset, x + 1, y + height - inset, color, path);
249
-   this.drawLine(x, y + height - inset, x, y + 1, color, path);// close the path
250
+   var renderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
251
+         this.strokeWidth, color);
252
+   renderer.beginStroke();
253
+   this.drawLineSegment(x, y, x + width - inset, y, renderer);
254
+   this.drawLineSegment(x + width - inset, y + 1, x + width - inset, y + height - inset,
255
+         renderer);
256
+   this.drawLineSegment(x + width - 1 - inset, y + height - inset, x + 1, y + height - inset,
257
+         renderer);
258
+   this.drawLineSegment(x, y + height - inset, x, y + 1, renderer);// close the path
259
    
260
-   this.strokesManager.applyStrokeToPath(this,
261
-         this.strokeStyleId,
262
-         this.strokeWidth,
263
-         color,
264
-         path);
265
 };
266
 
267
 /**
268
@@ -860,7 +869,7 @@
269
    var data = img.data;
270
    if (p2j.isChrome)
271
    {
272
-      copyImage(img, data, imgData, width, height, imgDataOffset);
273
+      this.copyImage(img, data, imgData, width, height, imgDataOffset);
274
    }
275
    else
276
    {
277
@@ -920,7 +929,7 @@
278
  *           Returns the modified screen image data array with the target image.
279
  *  
280
  */
281
-function copyImage(img, data, imgData, width, height, imgDataOffset)
282
+CanvasRenderer.prototype.copyImage = function(img, data, imgData, width, height, imgDataOffset)
283
 {
284
    var awidth  = img.width;
285
    var aheight = img.height;
286
@@ -1033,16 +1042,13 @@
287
    this.renderClosedPath(fill);
288
    
289
    // overdraw the anti-aliased line segments              
290
-   var path = [];
291
-   this.drawLine(topLeftX, topLeftY, topRightX, topRightY, color, path);
292
-   this.drawLine(rightUpX, rightUpY, rightDownX, rightDownY, color, path);
293
-   this.drawLine(bottomLeftX, bottomLeftY, bottomRightX, bottomRightY, color, path);
294
-   this.drawLine(leftUpX, leftUpY, leftDownX, leftDownY, color, path);
295
-   this.strokesManager.applyStrokeToPath(this,
296
-         this.strokeStyleId,
297
-         this.strokeWidth,
298
-         color,
299
-         path);
300
+   var renderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
301
+         this.strokeWidth, color);
302
+   renderer.beginStroke();
303
+   this.drawLineSegment(topLeftX, topLeftY, topRightX, topRightY, renderer);
304
+   this.drawLineSegment(rightUpX, rightUpY, rightDownX, rightDownY, renderer);
305
+   this.drawLineSegment(bottomLeftX, bottomLeftY, bottomRightX, bottomRightY, renderer);
306
+   this.drawLineSegment(leftUpX, leftUpY, leftDownX, leftDownY, renderer);
307
 };
308
 
309
 /**
310
@@ -1108,29 +1114,24 @@
311
    }
312
    
313
    current = raised ? lighter : darker;
314
-   
315
+   var renderer1 = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
316
+         this.strokeWidth, current);
317
+   renderer1.beginStroke();
318
    // draw the top and left sides in the contrasting color (raised mode) or the darker color
319
    // otherwise
320
-   var path = [];// create new pixels path to draw
321
-   this.drawLine(x, y, x + width - 2 - inset, y, current, path);
322
-   this.drawLine(x, y + 1, x, y + height - 1 - inset, current, path);
323
-   this.strokesManager.applyStrokeToPath(this,
324
-         this.strokeStyleId,
325
-         this.strokeWidth,
326
-         current,
327
-         path);
328
+   this.drawLineSegment(x, y, x + width - 2 - inset, y, renderer1);
329
+   this.drawLineSegment(x, y + 1, x, y + height - 1 - inset, renderer1);
330
 
331
    // draw the bottom and right sides in the darker color (raised mode) or the contrasting
332
    // color otherwise
333
    current = raised ? darker : lighter;
334
-   path = []; // create new pixels path to draw
335
-   this.drawLine(x + 1, y + height - 1 - inset, x + width - 1 - inset, y + height - 1 - inset, current, path);
336
-   this.drawLine(x + width - 1 - inset, y, x + width - 1 - inset, y + height - 2, current, path);
337
-   this.strokesManager.applyStrokeToPath(this,
338
-         this.strokeStyleId,
339
-         this.strokeWidth,
340
-         current,
341
-         path);
342
+   var renderer2 = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
343
+         this.strokeWidth, current);
344
+   renderer2.beginStroke();
345
+   this.drawLineSegment(x + 1, y + height - 1 - inset, x + width - 1 - inset,
346
+         y + height - 1 - inset, renderer2);
347
+   this.drawLineSegment(x + width - 1 - inset, y, x + width - 1 - inset, y + height - 2,
348
+         renderer2);
349
    
350
    // clear the clipping region
351
    this.ctx.restore();
352
@@ -1154,8 +1155,6 @@
353
  * @param    {Boolean} fill
354
  *           <code>true</code> to fill the rectangle with the current color, otherwise just
355
  *           stroke the rectangle.
356
- * @return   {Array}
357
- *           The {x:.,y:.} point per a pixel array that represents this poligon.
358
  */
359
 CanvasRenderer.prototype.drawPolygon = function(xPoints, yPoints, num, color, fill)
360
 {
361
@@ -1173,15 +1172,17 @@
362
       this.ctx.closePath();
363
       this.renderClosedPath(fill);
364
    }
365
-   var path = [];
366
+   var renderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
367
+         this.strokeWidth, color);
368
+   renderer.beginStroke();
369
+
370
    // now overdraw the stroked portion
371
    for (i = 0; i < (num - 1); i++)
372
    {
373
-      this.drawLine(xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1], color, path);
374
+      this.drawLineSegment(xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1], renderer);
375
    }
376
    // close the path
377
-   this.drawLine(xPoints[num - 1], yPoints[num - 1], xPoints[0], yPoints[0], color, path);
378
-   return path;
379
+   this.drawLineSegment(xPoints[num - 1], yPoints[num - 1], xPoints[0], yPoints[0], renderer);
380
 };
381
 
382
 /**
383
@@ -1201,12 +1202,7 @@
384
  */
385
 CanvasRenderer.prototype.strokePolygon = function(xPoints, yPoints, num, color, fill)
386
 {
387
-   var path = this.drawPolygon(xPoints, yPoints, num, color, fill);
388
-   this.strokesManager.applyStrokeToPath(this,
389
-         this.strokeStyleId,
390
-         this.strokeWidth,
391
-         color,
392
-         path);
393
+   this.drawPolygon(xPoints, yPoints, num, color, fill);
394
 };
395
 
396
 /**
397
@@ -1717,7 +1713,7 @@
398
       var y1 = origY;
399
       var y2 = y1;
400
       
401
-      this.strokeLineSegment(this.ctx, x1, y1, x2, y2, this.rawColor);
402
+      this.strokeLineSegment(x1, y1, x2, y2, this.rawColor);
403
    }
404
 }
405
 
406

    
407
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js'
408
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js	2016-02-17 20:45:29 +0000
409
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js	2016-02-17 21:35:30 +0000
410
@@ -11,6 +11,7 @@
411
 ** -#- -I- --Date-- ------------------------------Description----------------------------------
412
 ** 001 SBI 20150819 The first version defines LineStrokes class as a strokes manager.
413
 ** 002 SBI 20151012 Added XOR processing and dotted large line stroke support.
414
+** 003 SBI 20160215 Reduced putImageData invocations for horizontal and vertical lines.
415
 */
416
 
417
 "use strict";
418
@@ -193,7 +194,7 @@
419
     * 
420
     * @return   The stroke path renderer.
421
     */
422
-   function getStrokePathRenderer(canvasRenderer, strokeStyle, width, strokeColor)
423
+   this.getStrokePathRenderer = function(canvasRenderer, strokeStyle, width, strokeColor)
424
    {
425
       var basicStroke = getLineStroke(strokeStyle, width);
426
       
427
@@ -207,7 +208,7 @@
428
          case LineStrokeEnum.DOTTED_LARGE:
429
             return new DotsPathRenderer(canvasRenderer, basicStroke, strokeColor);
430
          default:
431
-            return { applyStroke : function (path) {} };
432
+            return new DefaultPathRenderer(canvasRenderer, strokeColor);
433
       }
434
    };
435
    
436
@@ -244,40 +245,8 @@
437
          context.lineDashOffset = basicStroke.getDashPhase();
438
       }
439
    }
440
-
441
-   /**
442
-    * Apply the given stroke style to the area outer bounds.
443
-    * 
444
-    * @param    {CanvasRenderer} canvasRenderer
445
-    *           The canvas renderer.
446
-    * @param    {Number} strokeStyle
447
-    *           The stroke style id.
448
-    * @param    {Number} width
449
-    *           The line width.
450
-    * @param    {Number[]} strokeColor
451
-    *           The array of 3 integer values between 0 and 255 inclusive, representing
452
-    *           a stroke color.
453
-    * @param    {Array} path
454
-    *           The array of points that forms the outline of the target area.
455
-    */
456
-   this.applyStrokeToPath = function(canvasRenderer, strokeStyle, width, strokeColor, path)
457
-   {
458
-      var renderer = getStrokePathRenderer(canvasRenderer, strokeStyle, width, strokeColor);
459
-      renderer.applyStroke(path);
460
-   }
461
    
462
    /**
463
-    * Returns true if for the given stroke style it is supposed to draw lines and rectangles
464
-    * using drawing functions without any corrections of their results, otherwise, false.
465
-    * 
466
-    * @return   {boolean} true or false
467
-    */
468
-   this.isDirectDrawingStrokeStyle = function(strokeStyle)
469
-   {
470
-      return LineStrokeEnum.DEFAULT == strokeStyle;
471
-   }
472
-
473
-   /**
474
     * Returns the default stroke that is a solid line style with 1 pixel line width.
475
     * 
476
     * @return   {Number} The default stroke style.
477
@@ -288,6 +257,53 @@
478
    }
479
 
480
    /**
481
+    * Defines StrokeRenderer class
482
+    */
483
+   function StrokeRenderer()
484
+   {
485
+   }
486
+
487
+   /**
488
+    * Defines the constructor function
489
+    */
490
+   StrokeRenderer.prototype.constructor = StrokeRenderer;
491
+
492
+   /**
493
+    * Prepare the object.
494
+    */
495
+   StrokeRenderer.prototype.beginStroke = function()
496
+   {
497
+   };
498
+
499
+   /**
500
+    * Apply the stroke to lines given by the absolute coordinates.
501
+    * 
502
+    * @param    {Number} x1
503
+    *           X coordinate of the starting pixel to be drawn.
504
+    * @param    {Number} y1
505
+    *           Y coordinate of the starting pixel to be drawn.
506
+    * @param    {Number} x2
507
+    *           X coordinate of the ending pixel to be drawn.
508
+    * @param    {Number} y2
509
+    *           Y coordinate of the ending pixel to be drawn.
510
+    */
511
+   StrokeRenderer.prototype.strokeLine  = function(x1, y1, x2, y2)
512
+   {
513
+   };
514
+   
515
+   /**
516
+    * Apply the stroke to the next point given by its coordinates (x, y).
517
+    * 
518
+    * @param    {Number} x
519
+    *           X coordinate of the point to be drawn.
520
+    * @param    {Number} y
521
+    *           Y coordinate of the point to be drawn.
522
+    */
523
+   StrokeRenderer.prototype.strokePoint = function(x, y)
524
+   {
525
+   };
526
+   
527
+   /**
528
     * Used to draw dash patterns on lines of pixels.
529
     * 
530
     * @param    {CanvasRenderer} canvasRenderer
531
@@ -303,6 +319,7 @@
532
       var pixel = canvasRenderer.createImageData(1, 1);
533
       var pixelData = pixel.data;
534
       pixelData[3] = 0xFF;
535
+      var state = {};
536
 
537
       /**
538
        * Normalizes a dash offset distance according to the given dash pattern.
539
@@ -339,12 +356,9 @@
540
       }
541
       
542
       /**
543
-       * Apply the given stroke to the line of pixels called a path.
544
-       * 
545
-       * @param    {Array} path
546
-       *           The array of points that forms the outline of the target area.
547
+       * Prepares the given stroke to be applied to the line of pixels called a path.
548
        */
549
-      this.applyStroke = function (path)
550
+      this.beginStroke = function()
551
       {
552
          var dash = basicStroke.getDash();
553
          if (!dash || dash.length == 0)
554
@@ -361,28 +375,113 @@
555
          var idx    = patternObj.startIdx;
556
          var rest = dash[idx] - phase;
557
          
558
-         for (var i = 0; i < path.length; i++)
559
+         state.dash   = dash;
560
+         state.len    = len;
561
+         state.dashOn = dashOn;
562
+         state.idx    = idx;
563
+         state.rest   = rest;
564
+      }
565
+      
566
+      /**
567
+       * Apply the stroke to vertical or horizontal lines given by the absolute coordinates that
568
+       * satisfy x1 <= x2 and y1 <= y2.
569
+       * 
570
+       * @param    {Number} x1
571
+       *           X coordinate of the starting pixel to be drawn.
572
+       * @param    {Number} y1
573
+       *           Y coordinate of the starting pixel to be drawn.
574
+       * @param    {Number} x2
575
+       *           X coordinate of the ending pixel to be drawn.
576
+       * @param    {Number} y2
577
+       *           Y coordinate of the ending pixel to be drawn.
578
+       */
579
+      this.strokeLine = function(x1, y1, x2, y2)
580
+      {
581
+         var rest   = state.rest;
582
+         var idx    = state.idx;
583
+         var len    = state.len;
584
+         var dashOn = state.dashOn;
585
+         var dash   = state.dash;
586
+         
587
+         var dx = x2 - x1;
588
+         var x = x1;
589
+         var y = y1;
590
+         while(x <= x2 && y <= y2)
591
          {
592
-            var point = path[i];
593
             if (rest < 1)
594
             {
595
-               idx = (idx + 1) % len;
596
-               rest = dash[idx];
597
+               idx    = (idx + 1) % len;
598
+               rest   = state.dash[idx];
599
                dashOn = !dashOn;
600
             }
601
             rest -= 1;
602
-
603
+            
604
             if (dashOn)
605
             {
606
                pixelData[0] = strokeColor[0];
607
                pixelData[1] = strokeColor[1];
608
                pixelData[2] = strokeColor[2];
609
-               canvasRenderer.putImageData(pixel, point.x, point.y);
610
-            }
611
-         }
612
+               canvasRenderer.putImageData(pixel, x, y);
613
+            }
614
+            if (dx === 0)
615
+            {
616
+               y = y + 1;
617
+            }
618
+            else
619
+            {
620
+               x = x + 1;
621
+            }
622
+         }
623
+         state.dashOn = dashOn;
624
+         state.rest   = rest;
625
+         state.idx    = idx;
626
+      }
627
+      
628
+      /**
629
+       * Apply the stroke to the next point given by its coordinates (x, y).
630
+       * 
631
+       * @param    {Number} x
632
+       *           X coordinate of the point to be drawn.
633
+       * @param    {Number} y
634
+       *           Y coordinate of the point to be drawn.
635
+       */
636
+      this.strokePoint = function(x, y)
637
+      {
638
+         var rest   = state.rest;
639
+         var idx    = state.idx;
640
+         var len    = state.len;
641
+         var dashOn = state.dashOn;
642
+         if (rest < 1)
643
+         {
644
+            idx    = (idx + 1) % len;
645
+            rest   = state.dash[idx];
646
+            dashOn = !dashOn;
647
+         }
648
+         rest -= 1;
649
+         if (dashOn)
650
+         {
651
+            pixelData[0] = strokeColor[0];
652
+            pixelData[1] = strokeColor[1];
653
+            pixelData[2] = strokeColor[2];
654
+            canvasRenderer.putImageData(pixel, x, y);
655
+         }
656
+         
657
+         state.dashOn = dashOn;
658
+         state.rest   = rest;
659
+         state.idx    = idx;
660
+      }
661
+      
662
+   }
663
+   
664
+   /**
665
+    * DotsPathRenderer implements StrokeRenderer methods
666
+    */
667
+   DotsPathRenderer.prototype = Object.create(StrokeRenderer.prototype);
668
 
669
-      }
670
-   }
671
+   /**
672
+    * Defines the constructor function
673
+    */
674
+   DotsPathRenderer.prototype.constructor = DotsPathRenderer;
675
    
676
    /**
677
     * Used to widen lines of pixels.
678
@@ -408,20 +507,156 @@
679
          imageData[i + 2] = strokeColor[2];
680
          imageData[i + 3] = 0xFF;
681
       }
682
-
683
-      /**
684
-       * To widen the line of pixels called a path according to the stroke style.
685
-       * 
686
-       * @param    {Array} path
687
-       *           The array of points that forms the outline of the target area.
688
-       */
689
-      this.applyStroke = function (path)
690
-      {
691
-         for (var i = 0; i < path.length; i++)
692
-         {
693
-            var point = path[i];
694
-            canvasRenderer.putImageData(image, point.x - (width >> 1), point.y - (width >> 1));
695
-         }
696
-      }
697
-   }
698
-}
699
\ No newline at end of file
700
+      
701
+      /**
702
+       * Prepares the given stroke to be applied to the line of pixels called a path.
703
+       */
704
+      this.beginStroke = function()
705
+      {
706
+      }
707
+      
708
+      /**
709
+       * Apply the stroke to vertical or horizontal lines given by the absolute coordinates that
710
+       * satisfy x1 <= x2 and y1 <= y2.
711
+       * 
712
+       * @param    {Number} x1
713
+       *           X coordinate of the starting pixel to be drawn.
714
+       * @param    {Number} y1
715
+       *           Y coordinate of the starting pixel to be drawn.
716
+       * @param    {Number} x2
717
+       *           X coordinate of the ending pixel to be drawn.
718
+       * @param    {Number} y2
719
+       *           Y coordinate of the ending pixel to be drawn.
720
+       */
721
+      this.strokeLine = function(x1, y1, x2, y2)
722
+      {
723
+         var lineWidth  = x2 - x1 + width;
724
+         var lineHeight = y2 - y1 + width;
725
+         var x0 = x1 - (width >> 1);
726
+         var y0 = y1 - (width >> 1);
727
+         var screenImage = canvasRenderer.ctx.createImageData(lineWidth, lineHeight);
728
+         var data = screenImage.data;
729
+         var length = 4 * lineWidth * lineHeight;
730
+         
731
+         for (var i = 0; i < length; i += 4)
732
+         {
733
+            data[i]     = strokeColor[0];
734
+            data[i + 1] = strokeColor[1];
735
+            data[i + 2] = strokeColor[2];
736
+            data[i + 3] = 255;
737
+         }
738
+         canvasRenderer.putImageData(screenImage, x0, y0);
739
+      }
740
+      
741
+      /**
742
+       * Apply the stroke to the next point given by its coordinates (x, y).
743
+       * 
744
+       * @param    {Number} x
745
+       *           X coordinate of the point to be drawn.
746
+       * @param    {Number} y
747
+       *           Y coordinate of the point to be drawn.
748
+       */
749
+      this.strokePoint = function(x, y)
750
+      {
751
+         canvasRenderer.putImageData(image, x - (width >> 1), y - (width >> 1));
752
+      }
753
+
754
+   }
755
+   
756
+   /**
757
+    * WidenPathRenderer implements StrokeRenderer methods
758
+    */
759
+   WidenPathRenderer.prototype = Object.create(StrokeRenderer.prototype);
760
+
761
+   /**
762
+    * Defines the constructor function
763
+    */
764
+   WidenPathRenderer.prototype.constructor = WidenPathRenderer;
765
+
766
+   /**
767
+    * The default lines renderer.
768
+    * 
769
+    * @param    {CanvasRenderer} canvasRenderer
770
+    *           The canvas renderer.
771
+    * @param    {Number[]} strokeColor
772
+    *           The array of 3 integer values between 0 and 255 inclusive, representing
773
+    *           a stroke color.
774
+    */
775
+   function DefaultPathRenderer(canvasRenderer, strokeColor)
776
+   {
777
+      var width = defaultStroke.getWidth();
778
+      var image = canvasRenderer.createImageData(width, width);
779
+      var imageData = image.data;
780
+      
781
+      for (var i = 0; i < 4 * width * width; i += 4)
782
+      {
783
+         imageData[i]     = strokeColor[0];
784
+         imageData[i + 1] = strokeColor[1];
785
+         imageData[i + 2] = strokeColor[2];
786
+         imageData[i + 3] = 255;
787
+      }
788
+      
789
+      /**
790
+       * Prepares the given stroke to be applied to the line of pixels called a path.
791
+       */
792
+      this.beginStroke = function()
793
+      {
794
+      }
795
+      
796
+      /**
797
+       * Apply the stroke to vertical or horizontal lines given by the absolute coordinates that
798
+       * satisfy x1 <= x2 and y1 <= y2.
799
+       * 
800
+       * @param    {Number} x1
801
+       *           X coordinate of the starting pixel to be drawn.
802
+       * @param    {Number} y1
803
+       *           Y coordinate of the starting pixel to be drawn.
804
+       * @param    {Number} x2
805
+       *           X coordinate of the ending pixel to be drawn.
806
+       * @param    {Number} y2
807
+       *           Y coordinate of the ending pixel to be drawn.
808
+       */
809
+      this.strokeLine = function(x1, y1, x2, y2)
810
+      {
811
+         var lineWidth  = x2 - x1 + 1;
812
+         var lineHeight = y2 - y1 + 1;
813
+         var screenImage = canvasRenderer.ctx.createImageData(lineWidth, lineHeight);
814
+         var data = screenImage.data;
815
+         var length = 4 * lineWidth * lineHeight;
816
+         
817
+         for (var i = 0; i < length; i += 4)
818
+         {
819
+            data[i]     = strokeColor[0];
820
+            data[i + 1] = strokeColor[1];
821
+            data[i + 2] = strokeColor[2];
822
+            data[i + 3] = 255;
823
+         }
824
+         canvasRenderer.putImageData(screenImage, x1, y1);
825
+      }
826
+      
827
+      /**
828
+       * Apply the stroke to the next point given by its coordinates (x, y).
829
+       * 
830
+       * @param    {Number} x
831
+       *           X coordinate of the point to be drawn.
832
+       * @param    {Number} y
833
+       *           Y coordinate of the point to be drawn.
834
+       */
835
+      this.strokePoint = function(x, y)
836
+      {
837
+         canvasRenderer.putImageData(image, x, y);
838
+      }
839
+
840
+   }
841
+
842
+   /**
843
+    * DefaultPathRenderer implements StrokeRenderer methods
844
+    */
845
+   DefaultPathRenderer.prototype = Object.create(StrokeRenderer.prototype);
846
+
847
+   /**
848
+    * Defines the constructor function
849
+    */
850
+   DefaultPathRenderer.prototype.constructor = DefaultPathRenderer;
851
+
852
+}
853