Enhance existing Animometer tests
[WebKit-https.git] / PerformanceTests / Animometer / tests / master / resources / image-data.js
1 (function() {
2
3 var ImageDataStage = Utilities.createSubclass(Stage,
4     function() {
5         Stage.call(this);
6
7         this.testElements = [];
8         this._offsetIndex = 0;
9     }, {
10
11     imageWidth: 100,
12     imageHeight: 100,
13     pixelStride: 4,
14     rowStride: 400,
15     weightNegativeThreshold: 0.04,
16     weightPositiveThreshold: 0.96,
17     imageSrcs: [
18         "compass",
19         "console",
20         "contribute",
21         "debugger",
22         "inspector",
23         "layout",
24         "performance",
25         "script",
26         "shortcuts",
27         "standards",
28         "storage",
29         "styles",
30         "timeline"
31     ],
32     images: [],
33
34     initialize: function(benchmark)
35     {
36         Stage.prototype.initialize.call(this, benchmark);
37
38         var lastPromise;
39         var images = this.images;
40         this.imageSrcs.forEach(function(imageSrc) {
41             var promise = this._loadImage("resources/" + imageSrc + ".svg");
42             if (!lastPromise)
43                 lastPromise = promise;
44             else {
45                 lastPromise = lastPromise.then(function(img) {
46                     images.push(img);
47                     return promise;
48                 });
49             }
50         }, this);
51
52         lastPromise.then(function(img) {
53             images.push(img);
54             benchmark.readyPromise.resolve();
55         }.bind(this));
56     },
57
58     _loadImage: function(src) {
59         var img = new Image;
60         var promise = new SimplePromise;
61
62         img.addEventListener('load', function onImageLoad(e) {
63             img.removeEventListener('load', onImageLoad);
64             promise.resolve(img);
65         });
66
67         img.src = src;
68         return promise;
69     },
70
71     tune: function(count)
72     {
73         if (count == 0)
74             return;
75
76         if (count < 0) {
77             this._offsetIndex = Math.max(this._offsetIndex + count, 0);
78             for (var i = this._offsetIndex; i < this.testElements.length; ++i)
79                 this.testElements[i].style.display = "none";
80             return;
81         }
82
83         this._offsetIndex = this._offsetIndex + count;
84         var index = Math.min(this._offsetIndex, this.testElements.length);
85         for (var i = 0; i < index; ++i) {
86             this.testElements[i].style.display = "block";
87             this._refreshElement(this.testElements[i]);
88         }
89         if (this._offsetIndex <= this.testElements.length)
90             return;
91
92         index = this._offsetIndex - this.testElements.length;
93         for (var i = 0; i < index; ++i) {
94             var element = this._createTestElement();
95             this.testElements.push(element);
96             this.element.appendChild(element);
97         }
98     },
99
100     _createTestElement: function() {
101         var element = document.createElement('canvas');
102         element.width = this.imageWidth;
103         element.height = this.imageHeight;
104         element.style.width = this.imageWidth + 'px';
105         element.style.height = this.imageHeight + 'px';
106
107         this._refreshElement(element);
108         return element;
109     },
110
111     _refreshElement: function(element) {
112         var top = Stage.randomInt(0, Math.floor((this.size.height - this.imageHeight) / this.imageHeight)) * this.imageHeight;
113         var left = Stage.randomInt(0, Math.floor((this.size.width - this.imageWidth) / this.imageWidth)) * this.imageWidth;
114
115         element.style.top = top + 'px';
116         element.style.left = left + 'px';
117     },
118
119     animate: function(timeDelta) {
120         for (var i = 0; i < this._offsetIndex; ++i) {
121             var element = this.testElements[i];
122             var context = element.getContext("2d");
123
124             // Get image data
125             var imageData = context.getImageData(0, 0, this.imageWidth, this.imageHeight);
126
127             var didDraw = false,
128                 neighborPixelIndex,
129                 dataLen = imageData.data.length;
130             for (var j = 0; j < dataLen; j += this.pixelStride) {
131                 if (imageData.data[j + 3] === 0)
132                     continue;
133
134                 // get random neighboring pixel color
135                 neighborPixelIndex = this._getRandomNeighboringPixelIndex(j, dataLen);
136
137                 // Update the RGB data
138                 imageData.data[j] = imageData.data[neighborPixelIndex];
139                 imageData.data[j + 1] = imageData.data[neighborPixelIndex + 1];
140                 imageData.data[j + 2] = imageData.data[neighborPixelIndex + 2];
141                 imageData.data[j + 3] = imageData.data[neighborPixelIndex + 3];
142                 didDraw = true;
143             }
144
145             if (didDraw)
146                 context.putImageData(imageData, 0, 0);
147             else {
148                 this._refreshElement(element);
149                 element.getContext("2d").drawImage(this.images[Stage.randomInt(0, this.images.length - 1)], 0, 0, this.imageWidth, this.imageHeight);
150             }
151         }
152     },
153
154     _getRandomNeighboringPixelIndex: function(pixelIdx, pixelArrayLength)
155     {
156         var xOffset = Math.floor((Pseudo.random() - this.weightNegativeThreshold) / (this.weightPositiveThreshold - this.weightNegativeThreshold));
157         var yOffset = Math.floor((Pseudo.random() - this.weightNegativeThreshold) / (this.weightPositiveThreshold - this.weightNegativeThreshold));
158         return (pixelIdx + this.pixelStride * xOffset + this.rowStride * yOffset) % pixelArrayLength;
159     },
160
161     complexity: function()
162     {
163         return this._offsetIndex;
164     }
165 });
166
167 var ImageDataBenchmark = Utilities.createSubclass(Benchmark,
168     function(options)
169     {
170         Benchmark.call(this, new ImageDataStage(), options);
171     }, {
172
173     waitUntilReady: function() {
174         this.readyPromise = new SimplePromise;
175         return this.readyPromise;
176     }
177 });
178
179 window.benchmarkClass = ImageDataBenchmark;
180
181 }());