@@ -98,41 +98,112 @@ var _Browser_document = __Debugger_document || F4(function(impl, flagDecoder, de
9898// ANIMATION
9999
100100
101- var _Browser_cancelAnimationFrame =
102- typeof cancelAnimationFrame !== 'undefined'
103- ? cancelAnimationFrame
104- : function ( id ) { clearTimeout ( id ) ; } ;
101+ var _Browser_requestAnimationFrame_queue = { } ;
102+ var _Browser_inAnimationFrame = false ;
103+ var _Browser_pendingAnimationFrame = false ;
104+ var _Browser_requestAnimationFrame_id = 0 ;
105105
106- var _Browser_requestAnimationFrame =
106+ function _Browser_cancelAnimationFrame ( id )
107+ {
108+ delete _Browser_requestAnimationFrame_queue [ id ] ;
109+ }
110+
111+ function _Browser_requestAnimationFrame ( callback )
112+ {
113+ var id = _Browser_requestAnimationFrame_id ;
114+ _Browser_requestAnimationFrame_id ++ ;
115+ _Browser_requestAnimationFrame_queue [ id ] = callback ;
116+ if ( ! _Browser_pendingAnimationFrame )
117+ {
118+ _Browser_pendingAnimationFrame = true ;
119+ _Browser_requestAnimationFrame_raw ( function ( ) {
120+ _Browser_pendingAnimationFrame = false ;
121+ _Browser_inAnimationFrame = true ;
122+ var maxId = _Browser_requestAnimationFrame_id ;
123+ for ( var id2 in _Browser_requestAnimationFrame_queue )
124+ {
125+ if ( id2 >= maxId )
126+ {
127+ break ;
128+ }
129+ var callback = _Browser_requestAnimationFrame_queue [ id2 ] ;
130+ delete _Browser_requestAnimationFrame_queue [ id2 ] ;
131+ callback ( ) ;
132+ }
133+ _Browser_inAnimationFrame = false ;
134+ } ) ;
135+ }
136+ return id ;
137+ }
138+
139+ var _Browser_requestAnimationFrame_raw =
107140 typeof requestAnimationFrame !== 'undefined'
108141 ? requestAnimationFrame
109142 : function ( callback ) { return setTimeout ( callback , 1000 / 60 ) ; } ;
110143
111-
112144function _Browser_makeAnimator ( model , draw )
113145{
114- draw ( model ) ;
146+ // Whether `draw` is currently running. `draw` can cause side effects:
147+ // If the user renders a custom element, they can dispatch an event in
148+ // its `connectedCallback`, which happens synchronously. That causes
149+ // `update` to run while we’re in the middle of drawing, which then
150+ // causes another call to the returned function below. We can’t start
151+ // another draw while before the first one is finished.
152+ var drawing = false ;
115153
116- var state = __4_NO_REQUEST ;
154+ // Whether we have already requested an animation frame for drawing.
155+ var pendingFrame = false ;
156+
157+ // Whether we have already requested to draw right after the current draw has finished.
158+ var pendingSync = false ;
159+
160+ function drawHelp ( )
161+ {
162+ // If we’re already drawing, wait until that draw is done.
163+ if ( drawing )
164+ {
165+ pendingSync = true ;
166+ return ;
167+ }
168+
169+ pendingFrame = false ;
170+ pendingSync = false ;
171+ drawing = true ;
172+ draw ( model ) ;
173+ drawing = false ;
174+
175+ if ( pendingSync )
176+ {
177+ drawHelp ( ) ;
178+ }
179+ }
117180
118181 function updateIfNeeded ( )
119182 {
120- state = state === __4_EXTRA_REQUEST
121- ? __4_NO_REQUEST
122- : ( _Browser_requestAnimationFrame ( updateIfNeeded ) , draw ( model ) , __4_EXTRA_REQUEST ) ;
183+ if ( pendingFrame )
184+ {
185+ drawHelp ( ) ;
186+ }
123187 }
124188
189+ drawHelp ( ) ;
190+
125191 return function ( nextModel , isSync )
126192 {
127193 model = nextModel ;
128194
129- isSync
130- ? ( draw ( model ) ,
131- state === __4_PENDING_REQUEST && ( state = __4_EXTRA_REQUEST )
132- )
133- : ( state === __4_NO_REQUEST && _Browser_requestAnimationFrame ( updateIfNeeded ) ,
134- state = __4_PENDING_REQUEST
135- ) ;
195+ // When using `Browser.Events.onAnimationFrame` we already are
196+ // in an animation frame, so draw straight away. Otherwise we’ll
197+ // be drawing one frame late all the time.
198+ if ( isSync || _Browser_inAnimationFrame )
199+ {
200+ drawHelp ( ) ;
201+ }
202+ else if ( ! pendingFrame )
203+ {
204+ pendingFrame = true ;
205+ _Browser_requestAnimationFrame ( updateIfNeeded ) ;
206+ }
136207 } ;
137208}
138209
0 commit comments