comparison chrome/pageloader.js @ 202:0b38ce037298

Bug 661918 - Tp should wait for MozAfterPaint after onload. r=tnikkel,vlad
author Joel Maher <jmaher@mozilla.com>
date Wed, 14 Sep 2011 16:41:38 -0400
parents bffb8b1b0948
children 4dec1e56c677
comparison
equal deleted inserted replaced
201:bffb8b1b0948 202:0b38ce037298
65 var delay = 250; 65 var delay = 250;
66 var timeoutEvent = -1; 66 var timeoutEvent = -1;
67 var running = false; 67 var running = false;
68 var forceCC = true; 68 var forceCC = true;
69 69
70 var useMozAfterPaint = false;
71 var gPaintWindow = window;
72 var gPaintListener = false;
73
74 //when TEST_DOES_OWN_TIMING, we need to store the time from the page as MozAfterPaint can be slower than pageload
75 var gTime = -1;
76 var gStartTime = -1;
77
70 var content; 78 var content;
71 79
72 var TEST_DOES_OWN_TIMING = 1; 80 var TEST_DOES_OWN_TIMING = 1;
73 81
74 var browserWindow = null; 82 var browserWindow = null;
98 if (args.height) winHeight = parseInt(args.height); 106 if (args.height) winHeight = parseInt(args.height);
99 if (args.filter) pageFilterRegexp = new RegExp(args.filter); 107 if (args.filter) pageFilterRegexp = new RegExp(args.filter);
100 if (args.noisy) noisy = true; 108 if (args.noisy) noisy = true;
101 if (args.timeout) timeout = parseInt(args.timeout); 109 if (args.timeout) timeout = parseInt(args.timeout);
102 if (args.delay) delay = parseInt(args.delay); 110 if (args.delay) delay = parseInt(args.delay);
111 if (args.mozafterpaint) useMozAfterPaint = true;
112
103 forceCC = !args.noForceCC; 113 forceCC = !args.noForceCC;
104 doRenderTest = args.doRender; 114 doRenderTest = args.doRender;
105 115
106 if (forceCC && 116 if (forceCC &&
107 !window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) 117 !window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
153 blank.data = "about:blank"; 163 blank.data = "about:blank";
154 browserWindow = wwatch.openWindow 164 browserWindow = wwatch.openWindow
155 (null, "chrome://browser/content/", "_blank", 165 (null, "chrome://browser/content/", "_blank",
156 "chrome,all,dialog=no,width=" + winWidth + ",height=" + winHeight, blank); 166 "chrome,all,dialog=no,width=" + winWidth + ",height=" + winHeight, blank);
157 167
168 gPaintWindow = browserWindow;
158 // get our window out of the way 169 // get our window out of the way
159 window.resizeTo(10,10); 170 window.resizeTo(10,10);
160 171
161 var browserLoadFunc = function (ev) { 172 var browserLoadFunc = function (ev) {
162 browserWindow.removeEventListener('load', browserLoadFunc, true); 173 browserWindow.removeEventListener('load', browserLoadFunc, true);
171 182
172 content = browserWindow.getBrowser(); 183 content = browserWindow.getBrowser();
173 184
174 // Load the frame script for e10s / IPC message support 185 // Load the frame script for e10s / IPC message support
175 if (content.getAttribute("remote") == "true") { 186 if (content.getAttribute("remote") == "true") {
176 let contentScript = "data:,addEventListener('load', function(e) { " + 187 let contentScript = "data:,function _contentLoadHandler(e) { " +
177 " if (e.originalTarget.defaultView == content) { " + 188 " if (e.originalTarget.defaultView == content) { " +
178 " sendAsyncMessage('PageLoader:Load', {}); " + 189 " content.wrappedJSObject.tpRecordTime = function(t, s) { sendAsyncMessage('PageLoader:RecordTime', { time: t, startTime: s }); }; ";
179 " content.wrappedJSObject.tpRecordTime = function(t) { sendAsyncMessage('PageLoader:RecordTime', { time: t }); } " + 190 if (useMozAfterPaint) {
191 contentScript += "" +
192 "function _contentPaintHandler() { " +
193 " var utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils); " +
194 " if (utils.isMozAfterPaintPending) { " +
195 " addEventListener('MozAfterPaint', function(e) { " +
196 " removeEventListener('MozAfterPaint', arguments.callee, true); " +
197 " sendAsyncMessage('PageLoader:MozAfterPaint', {}); " +
198 " }, true); " +
199 " } else { " +
200 " sendAsyncMessage('PageLoader:MozAfterPaint', {}); " +
201 " } " +
202 "}; " +
203 "content.wrappedJSObject.setTimeout(_contentPaintHandler, 0); ";
204 } else {
205 contentScript += " sendAsyncMessage('PageLoader:Load', {}); ";
206 }
207 contentScript += "" +
180 " }" + 208 " }" +
181 "}, true);" 209 "} " +
210 "addEventListener('load', _contentLoadHandler, true); ";
182 content.messageManager.loadFrameScript(contentScript, false); 211 content.messageManager.loadFrameScript(contentScript, false);
183 } 212 }
184 213
185 setTimeout(plLoadPage, 100); 214 setTimeout(plLoadPage, 100);
186 }, 500); 215 }, 500);
187 }; 216 };
188 217
189 browserWindow.addEventListener('load', browserLoadFunc, true); 218 browserWindow.addEventListener('load', browserLoadFunc, true);
190 } else { 219 } else {
220 gPaintWindow = window;
191 window.resizeTo(winWidth, winHeight); 221 window.resizeTo(winWidth, winHeight);
192 222
193 content = document.getElementById('contentPageloader'); 223 content = document.getElementById('contentPageloader');
194 224
195 setTimeout(plLoadPage, delay); 225 setTimeout(plLoadPage, delay);
217 removeLastAddedMsgListener(); 247 removeLastAddedMsgListener();
218 248
219 if (plPageFlags() & TEST_DOES_OWN_TIMING) { 249 if (plPageFlags() & TEST_DOES_OWN_TIMING) {
220 // if the page does its own timing, use a capturing handler 250 // if the page does its own timing, use a capturing handler
221 // to make sure that we can set up the function for content to call 251 // to make sure that we can set up the function for content to call
252
222 content.addEventListener('load', plLoadHandlerCapturing, true); 253 content.addEventListener('load', plLoadHandlerCapturing, true);
223 removeLastAddedListener = function() { 254 removeLastAddedListener = function() {
224 content.removeEventListener('load', plLoadHandlerCapturing, true); 255 content.removeEventListener('load', plLoadHandlerCapturing, true);
256 if (useMozAfterPaint) {
257 content.removeEventListener("MozAfterPaint", plPaintedCapturing, true);
258 gPaintHandler = false;
259 }
225 }; 260 };
226 } else { 261 } else {
227 // if the page doesn't do its own timing, use a bubbling handler 262 // if the page doesn't do its own timing, use a bubbling handler
228 // to make sure that we're called after the page's own onload() handling 263 // to make sure that we're called after the page's own onload() handling
229 264
230 // XXX we use a capturing event here too -- load events don't bubble up 265 // XXX we use a capturing event here too -- load events don't bubble up
231 // to the <browser> element. See bug 390263. 266 // to the <browser> element. See bug 390263.
232 content.addEventListener('load', plLoadHandler, true); 267 content.addEventListener('load', plLoadHandler, true);
233 removeLastAddedListener = function() { 268 removeLastAddedListener = function() {
234 content.removeEventListener('load', plLoadHandler, true); 269 content.removeEventListener('load', plLoadHandler, true);
270 if (useMozAfterPaint) {
271 gPaintWindow.removeEventListener("MozAfterPaint", plPainted, true);
272 gPaintHandler = false;
273 }
235 }; 274 };
236 } 275 }
237 276
238 // If the test browser is remote (e10s / IPC) we need to use messages to watch for page load 277 // If the test browser is remote (e10s / IPC) we need to use messages to watch for page load
239 if (content.getAttribute("remote") == "true") { 278 if (content.getAttribute("remote") == "true") {
240 content.messageManager.addMessageListener('PageLoader:Load', plLoadHandlerMessage); 279 content.messageManager.addMessageListener('PageLoader:Load', plLoadHandlerMessage);
241 content.messageManager.addMessageListener('PageLoader:RecordTime', plRecordTimeMessage); 280 content.messageManager.addMessageListener('PageLoader:RecordTime', plRecordTimeMessage);
281 if (useMozAfterPaint)
282 content.messageManager.addMessageListener('PageLoader:MozAfterPaint', plPaintHandler);
242 removeLastAddedMsgListener = function() { 283 removeLastAddedMsgListener = function() {
243 content.messageManager.removeMessageListener('PageLoader:Load', plLoadHandlerMessage); 284 content.messageManager.removeMessageListener('PageLoader:Load', plLoadHandlerMessage);
244 content.messageManager.removeMessageListener('PageLoader:RecordTime', plRecordTimeMessage); 285 content.messageManager.removeMessageListener('PageLoader:RecordTime', plRecordTimeMessage);
286 if (useMozAfterPaint)
287 content.messageManager.removeMessageListener('PageLoader:MozAfterPaint', plPaintHandler);
245 }; 288 };
246 } 289 }
247 290
248 if (timeout > 0) { 291 if (timeout > 0) {
249 timeoutEvent = setTimeout('loadFail()', timeout); 292 timeoutEvent = setTimeout('loadFail()', timeout);
295 function plLoadHandlerCapturing(evt) { 338 function plLoadHandlerCapturing(evt) {
296 // make sure we pick up the right load event 339 // make sure we pick up the right load event
297 if (evt.type != 'load' || 340 if (evt.type != 'load' ||
298 evt.originalTarget.defaultView.frameElement) 341 evt.originalTarget.defaultView.frameElement)
299 return; 342 return;
343
344 //set the tpRecordTime function (called from test pages we load to store a global time.
345 content.contentWindow.wrappedJSObject.tpRecordTime = function (time, startTime) {
346 gTime = time;
347 gStartTime = startTime;
348 setTimeout(plWaitForPaintingCapturing, 0);
349 }
350
351 content.removeEventListener('load', plLoadHandlerCapturing, true);
352
353 setTimeout(plWaitForPaintingCapturing, 0);
354 }
355
356 function plWaitForPaintingCapturing() {
357 if (gPaintListener)
358 return;
359
360 var utils = gPaintWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
361 .getInterface(Components.interfaces.nsIDOMWindowUtils);
362
363 if (utils.isMozAfterPaintPending && useMozAfterPaint) {
364 if (gPaintListener == false)
365 gPaintWindow.addEventListener("MozAfterPaint", plPaintedCapturing, true);
366 gPaintListener = true;
367 return;
368 }
369
370 _loadHandlerCapturing();
371 }
372
373 function plPaintedCapturing() {
374 gPaintWindow.removeEventListener("MozAfterPaint", plPaintedCapturing, true);
375 gPaintListener = false;
376 _loadHandlerCapturing();
377 }
378
379 function _loadHandlerCapturing() {
300 if (timeout > 0) { 380 if (timeout > 0) {
301 clearTimeout(timeoutEvent); 381 clearTimeout(timeoutEvent);
302 } 382 }
303 383
304 if (!(plPageFlags() & TEST_DOES_OWN_TIMING)) { 384 if (!(plPageFlags() & TEST_DOES_OWN_TIMING)) {
305 dumpLine("tp: Capturing onload handler used with page that doesn't do its own timing?"); 385 dumpLine("tp: Capturing onload handler used with page that doesn't do its own timing?");
306 plStop(true); 386 plStop(true);
307 } 387 }
308 388
389 if (useMozAfterPaint) {
390 if (gStartTime != null && gStartTime >= 0) {
391 gTime = (new Date()) - gStartTime;
392 gStartTime = -1;
393 }
394 }
395
309 // set up the function for content to call 396 // set up the function for content to call
310 content.contentWindow.wrappedJSObject.tpRecordTime = function (time) { 397 if (gTime >= 0) {
311 plRecordTime(time); 398 plRecordTime(gTime);
399 gTime = -1;
312 setTimeout(plNextPage, delay); 400 setTimeout(plNextPage, delay);
313 }; 401 };
314 } 402 }
315 403
316 // the onload handler 404 // the onload handler
317 function plLoadHandler(evt) { 405 function plLoadHandler(evt) {
318 // make sure we pick up the right load event 406 // make sure we pick up the right load event
319 if (evt.type != 'load' || 407 if (evt.type != 'load' ||
320 evt.originalTarget.defaultView.frameElement) 408 evt.originalTarget.defaultView.frameElement)
321 return; 409 return;
410
411 content.removeEventListener('load', plLoadHandler, true);
412 setTimeout(waitForPainted, 0);
413 }
414
415 // This is called after we have received a load event, now we wait for painted
416 function waitForPainted() {
417
418 var utils = gPaintWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
419 .getInterface(Components.interfaces.nsIDOMWindowUtils);
420
421 if (!utils.isMozAfterPaintPending || !useMozAfterPaint) {
422 _loadHandler();
423 return;
424 }
425
426 if (gPaintListener == false)
427 gPaintWindow.addEventListener("MozAfterPaint", plPainted, true);
428 gPaintListener = true;
429 }
430
431 function plPainted() {
432 gPaintWindow.removeEventListener("MozAfterPaint", plPainted, true);
433 gPaintListener = false;
434 _loadHandler();
435 }
436
437 function _loadHandler() {
322 if (timeout > 0) { 438 if (timeout > 0) {
323 clearTimeout(timeoutEvent); 439 clearTimeout(timeoutEvent);
324 } 440 }
325 var docElem; 441 var docElem;
326 if (browserWindow) 442 if (browserWindow)
352 plNextPage(); 468 plNextPage();
353 } 469 }
354 470
355 // the onload handler used for remote (e10s) browser 471 // the onload handler used for remote (e10s) browser
356 function plLoadHandlerMessage(message) { 472 function plLoadHandlerMessage(message) {
473 _loadHandlerMessage();
474 }
475
476 // the mozafterpaint handler for remote (e10s) browser
477 function plPaintHandler(message) {
478 _loadHandlerMessage();
479 }
480
481 // the core handler for remote (e10s) browser
482 function _loadHandlerMessage() {
357 if (timeout > 0) { 483 if (timeout > 0) {
358 clearTimeout(timeoutEvent); 484 clearTimeout(timeoutEvent);
359 } 485 }
360 486
487 var time = -1;
488
361 // does this page want to do its own timing? 489 // does this page want to do its own timing?
362 // if so, let's bail 490 if ((plPageFlags() & TEST_DOES_OWN_TIMING)) {
363 if (plPageFlags() & TEST_DOES_OWN_TIMING) 491 if (typeof(gStartTime) != "number")
364 return; 492 gStartTime = Date.parse(gStartTime);
365 493
366 var end_time = Date.now(); 494 if (gTime >= 0) {
367 var time = (end_time - start_time); 495 if (useMozAfterPaint && gStartTime >= 0) {
368 496 gTime = Date.now() - gStartTime;
369 plRecordTime(time); 497 gStartTime = -1;
370 498 } else if (useMozAfterPaint) {
371 if (doRenderTest) 499 gTime = -1;
372 runRenderTest(); 500 }
373 501 time = gTime;
374 plNextPage(); 502 gTime = -1;
503 }
504
505 } else {
506 var end_time = Date.now();
507 time = (end_time - start_time);
508 }
509
510 if (time >= 0) {
511 plRecordTime(time);
512 if (doRenderTest)
513 runRenderTest();
514
515 plNextPage();
516 }
375 } 517 }
376 518
377 // the record time handler used for remote (e10s) browser 519 // the record time handler used for remote (e10s) browser
378 function plRecordTimeMessage(message) { 520 function plRecordTimeMessage(message) {
379 plRecordTime(message.json.time); 521 gTime = message.json.time;
380 setTimeout(plNextPage, delay); 522 if (useMozAfterPaint) {
523 gStartTime = message.json.startTime;
524 }
525 _loadHandlerMessage();
381 } 526 }
382 527
383 function runRenderTest() { 528 function runRenderTest() {
384 const redrawsPerSample = 500; 529 const redrawsPerSample = 500;
385 530
427 } catch (e) { 572 } catch (e) {
428 dumpLine(e); 573 dumpLine(e);
429 } 574 }
430 575
431 if (content) { 576 if (content) {
577 content.removeEventListener('load', plLoadHandlerCapturing, true);
432 content.removeEventListener('load', plLoadHandler, true); 578 content.removeEventListener('load', plLoadHandler, true);
433 if (content.getAttribute("remote") == "true") 579 if (useMozAfterPaint)
580 content.removeEventListener("MozAfterPaint", plPaintedCapturing, true);
581 content.removeEventListener("MozAfterPaint", plPainted, true);
582
583 if (content.getAttribute("remote") == "true") {
434 content.messageManager.removeMessageListener('PageLoader:Load', plLoadHandlerMessage); 584 content.messageManager.removeMessageListener('PageLoader:Load', plLoadHandlerMessage);
585 content.messageManager.removeMessageListener('PageLoader:RecordTime', plRecordTimeMessage);
586 if (MozAfterPaint)
587 content.messageManager.removeMessageListener('PageLoader:MozAfterPaint', plPaintHandler);
588
589 content.messageManager.loadFrameScript("data:,removeEventListener('load', _contentLoadHandler, true);", false);
590 }
435 } 591 }
436 592
437 if (MozillaFileLogger) 593 if (MozillaFileLogger)
438 MozillaFileLogger.close(); 594 MozillaFileLogger.close();
439 595