This article needs a technical review. How you can help.
The MozAfterPaint
event is triggered when content is presented to the user on the screen and provides information about what has been repainted. It is mainly used to investigate performance optimization.
Note that MozAfterPaint is not fired immediately after painting has occurred, but after both painting and compositing have occurred. This means that when it fires, something has been presented to the user.
Note:
- This event is available to add-ons but since Firefox 4 it is not available to web pages by default. It can only be made available to web pages by setting the preference
dom.send_after_paint_to_content
totrue
. (Since Bug 539356, when this preference is set totrue
, all theMozAfterPaint
events are sent to web pages. See Bug 829330 for more information.) - Web pages that want to take an action after a repaint of the page can use requestAnimationFrame with a callback that sets a timeout of zero to then call the code that takes the desired post-repaint action.
- If the handler for this event does anything that triggers repainting (such as changing the style of an element), an infinite loop will probably be triggered.
- Repainting of areas scrolled outside the viewport is reported, but repainting of areas scrolled outside
overflow:auto
elements and the like is not. - Repainting in windowed plug-ins (which is most plug-ins on Windows and GTK) is not reported.
General info
- Specification
- Add-ons specific
- Interface
- Event
- Bubbles
- Yes
- Cancelable
- Yes
- Target
- window
- Default Action
- None
Properties
Property | Type | Description |
---|---|---|
target Read only |
EventTarget |
The event target (the topmost target in the DOM tree). |
type Read only |
DOMString |
The type of event. |
bubbles Read only |
boolean |
Does the event normally bubble? |
cancelable Read only |
boolean |
Is it possible to cancel the event? |
boundingClientRect |
clientRect | The equivalent of getBoundingClientRect() for the repainted zone. Read only. |
clientRects |
clientRectList | The equivalent of getClientRects() for the repainted zone. Read only. |
transactionId |
uint64_t |
The transaction id of the composition that just occurred to present something to the user. Read only. |
Example
This example highlights elements that get repainted while hovering the document with a cursor.
(function(){ var store = []; // every repaint will be logged in store window.addEventListener("MozAfterPaint", log, false); if ( document.body ) bind(); else window.addEventListener("load", bind, false); function log(e){ store.push( [(new Date).getTime(), e.clientRects] ); } function bind(){ // clicking anywhere on the document will prevent other repaint to be logged // as well as display the visual "repaint heatmap" document.body.addEventListener("click", function onClick(){ window.removeEventListener("MozAfterPaint", log, false); for ( var pos = 0; pos < store.length; pos++ ) { var rects = store[pos][1]; for ( var i = 0; i < rects.length; i++ ) { // will simply "draw" semi-transparent red divs where // repaints where recorded var rect = rects[i]; var div = document.createElement("div"); with (div.style) { background = "red"; opacity = "0.1"; position = "absolute"; top = rect.top + "px"; left = rect.left + "px"; width = (rect.right - rect.left) + "px"; height = (rect.bottom - rect.top) + "px"; } document.body.appendChild( div ); } } document.body.removeEventListener("click", onClick, false); }, false); } })();
This example is for measuring how long something took to paint to the user.
// Suppose we want to measure how long it takes to paint the // next frame after a click event is fired on element "target". let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); // The last transaction id is the last id that was sent to the // compositor before our script started to execute. let lastTransactionId = winUtils.lastTransactionId; let start = window.performance.now(); // Set up our MozAfterPaint listener, but we only care about // MozAfterPaint events where the transaction id is GREATER // than lastTransactionId. This is to account for the possibility // that a composite is underway at the time this script is running. addEventListener("MozAfterPaint", function onPaint(event) { if (event.transactionId > lastTransactionId) { // Since the transaction id is greater than the last transaction // id, that means we're safe to assume that whatever effect that // clicking on the "target" element was supposed to have, if the // change should have been instantaneous, then it has been presented // to the user. let finish = window.performance.now(); alert(`Time to present: ${finish - start}ms`); removeEventListener("MozAfterPaint", onPaint); } }); document.getElementById("target").click();