Project

General

Profile

performance_issue_3.txt

Sergey Ivanovskiy, 02/15/2016 04:40 PM

Download (28.7 KB)

 
1
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js'
2
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js	2016-02-13 21:56:51 +0000
3
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js	2016-02-15 21:28:46 +0000
4
@@ -498,15 +498,9 @@
5
  *           Y coordinate of the ending pixel to be drawn.
6
  * @param    {Number[]} color
7
  *           Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
8
- * 
9
- * @return   {Array} path
10
- *           The {x:.,y:.} point per a pixel array that represents the drawing line segment.
11
  */
12
 CanvasRenderer.prototype.drawLineSegment = function(x1, y1, x2, y2, color)
13
 {
14
-   // holds the line pixels to draw
15
-   var path = [];
16
-   
17
    x1 = x1 + this.origin.x;
18
    x2 = x2 + this.origin.x;
19
    
20
@@ -517,7 +511,7 @@
21
    var d = this.cutLine(x1, y1, x2, y2);
22
    if (d === null)
23
    {
24
-      return path;
25
+      return;
26
    }
27
    x1 = d[0];
28
    y1 = d[1];
29
@@ -527,60 +521,17 @@
30
    var dx = Math.abs(x2 - x1);
31
    var dy = Math.abs(y2 - y1);
32
    
33
-   var directStroke = this.strokesManager.isDirectDrawingStrokeStyle(this.strokeStyleId);
34
-   
35
+   var strokeRenderer = this.strokesManager.getStrokePathRenderer(this, this.strokeStyleId,
36
+         this.strokeWidth, color);
37
+   strokeRenderer.beginStroke();
38
    if (dx === 0 || dy === 0)
39
    {
40
-      var width  = dx + 1;
41
-      var height = dy + 1;
42
-      
43
-      var buffer = new ArrayBuffer(4 * width * height);
44
-      
45
-      var imageData = new Uint8ClampedArray(buffer);
46
-      
47
-      var x = x1;
48
-      var y = y1;
49
-      var curr = 0;
50
-      while(x <= x2 && y <= y2)
51
-      {
52
-         if (directStroke)
53
-         {
54
-            imageData[curr++] = color[0];
55
-            imageData[curr++] = color[1];
56
-            imageData[curr++] = color[2];
57
-            imageData[curr++] = 255;
58
-         }
59
-         path.push({x : x, y : y});
60
-         if (dy === 0)
61
-         {
62
-            x = x + 1;
63
-         }
64
-         else
65
-         {
66
-            y = y + 1;
67
-         }
68
-         
69
-      }
70
-      if (directStroke)
71
-      {
72
-         this.screenCapture = this.ctx.getImageData(x1, y1, width, height);
73
-         if (p2j.isChrome)
74
-         {
75
-            copyImage(this.screenCapture, this.screenCapture.data, imageData, width, height, 0);
76
-         }
77
-         else
78
-         {
79
-            this.screenCapture.data.set(imageData, 0);
80
-         }
81
-         this.ctx.putImageData(this.screenCapture, x1, y1);
82
-      }
83
+      strokeRenderer.strokeLine(x1, y1, x2, y2);
84
    }
85
    else
86
    {
87
-      path = drawSlopedLineSegment(this, x1, y1, x2, y2, color, directStroke);
88
+      this.drawSlopedLineSegment(x1, y1, x2, y2, strokeRenderer);
89
    }
90
-   
91
-   return path;
92
 };
93
 
94
 /**
95
@@ -588,8 +539,6 @@
96
  * <p>
97
  * This is an implementation of the well known 50+ year old Bresenham algorithm.
98
  *
99
- * @param    {CanvasRenderer} renderer
100
- *           The canvas renderer.
101
  * @param    {Number} x1
102
  *           X coordinate of the starting pixel to be drawn.
103
  * @param    {Number} y1
104
@@ -598,19 +547,11 @@
105
  *           X coordinate of the ending pixel to be drawn.
106
  * @param    {Number} y2
107
  *           Y coordinate of the ending pixel to be drawn.
108
- * @param    {Number[]} color
109
- *           Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
110
- * @param    {Boolean} draw
111
- *           True indicates that the line pixels are drawn on the canvas by the renderer.
112
- * 
113
- * @return   {Array} path
114
- *           The {x:.,y:.} point per a pixel array that represents the drawing line segment.
115
+ * @param    {StrokeRenderer} strokeRenderer
116
+ *           The current stroke renderer.
117
  */
118
-function drawSlopedLineSegment(renderer, x1, y1, x2, y2, color, draw)
119
+CanvasRenderer.prototype.drawSlopedLineSegment = function(x1, y1, x2, y2, strokeRenderer)
120
 {
121
-   // holds the line pixels to draw
122
-   var path = [];
123
-   
124
    var dx = Math.abs(x2 - x1);
125
    var dy = Math.abs(y2 - y1);
126
 
127
@@ -628,11 +569,7 @@
128
    
129
    while (true)
130
    {
131
-      if (draw)
132
-      {
133
-         renderer.drawPixel(x, y, color);
134
-      }
135
-      path.push({x : x, y : y});
136
+      strokeRenderer.strokePoint(x, y);
137
       
138
       tooMany++;
139
       
140
@@ -665,11 +602,10 @@
141
          y   += yIncr;
142
       }
143
    }
144
-   
145
-   return path;
146
 }
147
 
148
 /**
149
+ * 
150
  * Draw a line in the given color from (x1, y1) to (x2, y2) inclusive, using direct drawing and
151
  * add its pixels path to the end of the provided pixels path.
152
  * <p>
153
@@ -685,22 +621,14 @@
154
  *           Y coordinate of the ending pixel to be drawn.
155
  * @param    {Number[]} color
156
  *           Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
157
- * @param    {Array} path
158
- *           The provided holder of {x:.,y:.} points, the target drawing as a set of sequential
159
- *           line points will be added at the end of the provided path.
160
- * @return   {Array}
161
- *           The {x:.,y:.} point per a pixel array that represents the drawing line segment.
162
  */
163
-CanvasRenderer.prototype.drawLine = function(x1, y1, x2, y2, color, path)
164
+CanvasRenderer.prototype.drawLine = function(x1, y1, x2, y2, color)
165
 {
166
-   var segment = this.drawLineSegment(x1, y1, x2, y2, color);
167
-   Array.prototype.push.apply(path, segment);
168
-   return segment;
169
+   this.drawLineSegment(x1, y1, x2, y2, color);
170
 }
171
 
172
 /**
173
- * Stroke a line in the given color from (x1, y1) to (x2, y2) inclusive, using direct drawing and
174
- * add its pixels path to the end of the provided pixels path.
175
+ * Stroke a line in the given color from (x1, y1) to (x2, y2) inclusive.
176
  * <p>
177
  * This is an implementation of the well known 50+ year old Bresenham algorithm.
178
  *
179
@@ -714,18 +642,10 @@
180
  *           Y coordinate of the ending pixel to be drawn.
181
  * @param    {Number[]} color
182
  *           Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
183
- * @param    {Array} path
184
- *           The provided holder of {x:.,y:.} points, the target drawing as a set of sequential
185
- *           line points will be added at the end of the provided path.
186
  */
187
 CanvasRenderer.prototype.strokeLineSegment = function(x1, y1, x2, y2, color)
188
 {
189
-   var segment = this.drawLineSegment(x1, y1, x2, y2, color);
190
-   this.strokesManager.applyStrokeToPath(this,
191
-         this.strokeStyleId,
192
-         this.strokeWidth,
193
-         color,
194
-         segment);
195
+   this.drawLineSegment(x1, y1, x2, y2, color);
196
 }
197
 
198
 /**
199
@@ -745,15 +665,11 @@
200
  *           This will be used for the border lines and when in fill mode, also the interior.
201
  * @param    {Boolean} fill
202
  *           <code>true</code> to fill the drawn rectangle with the given color.
203
- * 
204
- * @return   {Array} path
205
- *           The {x:.,y:.} point per a pixel array that represents the rectangle outerline.
206
  */
207
 CanvasRenderer.prototype.drawRect = function(x, y, width, height, color, fill)
208
 {
209
    // filled rectangles draw 1 pixel smaller in 2 dimensions than stroked rectangles
210
    var inset = 0;
211
-   var path  = [];
212
    // use vector operations for the interior of the rectangle
213
    if (fill)
214
    {
215
@@ -765,12 +681,10 @@
216
    
217
    // now overdraw the stroked portion to eliminate anti-aliasing, we draw in a
218
    // clockwise direction (since we are not using paths, this is not strictly necessary)
219
-   this.drawLine(x, y, x + width - inset, y, color, path);
220
-   this.drawLine(x + width - inset, y + 1, x + width - inset, y + height - inset, color, path);
221
-   this.drawLine(x + width - 1 - inset, y + height - inset, x + 1, y + height - inset, color, path);
222
-   this.drawLine(x, y + height - inset, x, y + 1, color, path);// close the path
223
-   
224
-   return path;
225
+   this.drawLine(x, y, x + width - inset, y, color);
226
+   this.drawLine(x + width - inset, y + 1, x + width - inset, y + height - inset, color);
227
+   this.drawLine(x + width - 1 - inset, y + height - inset, x + 1, y + height - inset, color);
228
+   this.drawLine(x, y + height - inset, x, y + 1, color);// close the path
229
 };
230
 
231
 /**
232
@@ -795,7 +709,6 @@
233
 {
234
    // filled rectangles draw 1 pixel smaller in 2 dimensions than stroked rectangles
235
    var inset = 0;
236
-   var path  = [];
237
    // use vector operations for the interior of the rectangle
238
    if (fill)
239
    {
240
@@ -807,16 +720,11 @@
241
    
242
    // now overdraw the stroked portion to eliminate anti-aliasing, we draw in a
243
    // clockwise direction (since we are not using paths, this is not strictly necessary)
244
-   this.drawLine(x, y, x + width - inset, y, color, path);
245
-   this.drawLine(x + width - inset, y + 1, x + width - inset, y + height - inset, color, path);
246
-   this.drawLine(x + width - 1 - inset, y + height - inset, x + 1, y + height - inset, color, path);
247
-   this.drawLine(x, y + height - inset, x, y + 1, color, path);// close the path
248
+   this.drawLine(x, y, x + width - inset, y, color);
249
+   this.drawLine(x + width - inset, y + 1, x + width - inset, y + height - inset, color);
250
+   this.drawLine(x + width - 1 - inset, y + height - inset, x + 1, y + height - inset, color);
251
+   this.drawLine(x, y + height - inset, x, y + 1, color);// close the path
252
    
253
-   this.strokesManager.applyStrokeToPath(this,
254
-         this.strokeStyleId,
255
-         this.strokeWidth,
256
-         color,
257
-         path);
258
 };
259
 
260
 /**
261
@@ -864,7 +772,7 @@
262
    var data = img.data;
263
    if (p2j.isChrome)
264
    {
265
-      copyImage(img, data, imgData, width, height, imgDataOffset);
266
+      this.copyImage(img, data, imgData, width, height, imgDataOffset);
267
    }
268
    else
269
    {
270
@@ -924,7 +832,7 @@
271
  *           Returns the modified screen image data array with the target image.
272
  *  
273
  */
274
-function copyImage(img, data, imgData, width, height, imgDataOffset)
275
+CanvasRenderer.prototype.copyImage = function(img, data, imgData, width, height, imgDataOffset)
276
 {
277
    var awidth  = img.width;
278
    var aheight = img.height;
279
@@ -1037,16 +945,10 @@
280
    this.renderClosedPath(fill);
281
    
282
    // overdraw the anti-aliased line segments              
283
-   var path = [];
284
-   this.drawLine(topLeftX, topLeftY, topRightX, topRightY, color, path);
285
-   this.drawLine(rightUpX, rightUpY, rightDownX, rightDownY, color, path);
286
-   this.drawLine(bottomLeftX, bottomLeftY, bottomRightX, bottomRightY, color, path);
287
-   this.drawLine(leftUpX, leftUpY, leftDownX, leftDownY, color, path);
288
-   this.strokesManager.applyStrokeToPath(this,
289
-         this.strokeStyleId,
290
-         this.strokeWidth,
291
-         color,
292
-         path);
293
+   this.drawLine(topLeftX, topLeftY, topRightX, topRightY, color);
294
+   this.drawLine(rightUpX, rightUpY, rightDownX, rightDownY, color);
295
+   this.drawLine(bottomLeftX, bottomLeftY, bottomRightX, bottomRightY, color);
296
+   this.drawLine(leftUpX, leftUpY, leftDownX, leftDownY, color);
297
 };
298
 
299
 /**
300
@@ -1115,26 +1017,14 @@
301
    
302
    // draw the top and left sides in the contrasting color (raised mode) or the darker color
303
    // otherwise
304
-   var path = [];// create new pixels path to draw
305
-   this.drawLine(x, y, x + width - 2 - inset, y, current, path);
306
-   this.drawLine(x, y + 1, x, y + height - 1 - inset, current, path);
307
-   this.strokesManager.applyStrokeToPath(this,
308
-         this.strokeStyleId,
309
-         this.strokeWidth,
310
-         current,
311
-         path);
312
+   this.drawLine(x, y, x + width - 2 - inset, y, current);
313
+   this.drawLine(x, y + 1, x, y + height - 1 - inset, current);
314
 
315
    // draw the bottom and right sides in the darker color (raised mode) or the contrasting
316
    // color otherwise
317
    current = raised ? darker : lighter;
318
-   path = []; // create new pixels path to draw
319
-   this.drawLine(x + 1, y + height - 1 - inset, x + width - 1 - inset, y + height - 1 - inset, current, path);
320
-   this.drawLine(x + width - 1 - inset, y, x + width - 1 - inset, y + height - 2, current, path);
321
-   this.strokesManager.applyStrokeToPath(this,
322
-         this.strokeStyleId,
323
-         this.strokeWidth,
324
-         current,
325
-         path);
326
+   this.drawLine(x + 1, y + height - 1 - inset, x + width - 1 - inset, y + height - 1 - inset, current);
327
+   this.drawLine(x + width - 1 - inset, y, x + width - 1 - inset, y + height - 2, current);
328
    
329
    // clear the clipping region
330
    this.ctx.restore();
331
@@ -1158,8 +1048,6 @@
332
  * @param    {Boolean} fill
333
  *           <code>true</code> to fill the rectangle with the current color, otherwise just
334
  *           stroke the rectangle.
335
- * @return   {Array}
336
- *           The {x:.,y:.} point per a pixel array that represents this poligon.
337
  */
338
 CanvasRenderer.prototype.drawPolygon = function(xPoints, yPoints, num, color, fill)
339
 {
340
@@ -1177,15 +1065,13 @@
341
       this.ctx.closePath();
342
       this.renderClosedPath(fill);
343
    }
344
-   var path = [];
345
    // now overdraw the stroked portion
346
    for (i = 0; i < (num - 1); i++)
347
    {
348
-      this.drawLine(xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1], color, path);
349
+      this.drawLine(xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1], color);
350
    }
351
    // close the path
352
-   this.drawLine(xPoints[num - 1], yPoints[num - 1], xPoints[0], yPoints[0], color, path);
353
-   return path;
354
+   this.drawLine(xPoints[num - 1], yPoints[num - 1], xPoints[0], yPoints[0], color);
355
 };
356
 
357
 /**
358
@@ -1205,12 +1091,7 @@
359
  */
360
 CanvasRenderer.prototype.strokePolygon = function(xPoints, yPoints, num, color, fill)
361
 {
362
-   var path = this.drawPolygon(xPoints, yPoints, num, color, fill);
363
-   this.strokesManager.applyStrokeToPath(this,
364
-         this.strokeStyleId,
365
-         this.strokeWidth,
366
-         color,
367
-         path);
368
+   this.drawPolygon(xPoints, yPoints, num, color, fill);
369
 };
370
 
371
 /**
372
@@ -1721,7 +1602,7 @@
373
       var y1 = origY;
374
       var y2 = y1;
375
       
376
-      this.strokeLineSegment(this.ctx, x1, y1, x2, y2, this.rawColor);
377
+      this.strokeLineSegment(x1, y1, x2, y2, this.rawColor);
378
    }
379
 }
380
 
381

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