Bug 1302493 - Update the in-tree APZ documentation to reflect various changes since it was last updated. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 13 Sep 2016 13:59:56 -0400
changeset 413131 54ceeea841e2d7a347bfa9193bb9dc458559ca42
parent 413053 f5d043ce6d36a3c461cbd829d4a4a38394b7c436
child 531152 413bd8b8901c6bae69915d226614ec500d584325
push id29351
push userkgupta@mozilla.com
push dateTue, 13 Sep 2016 18:01:02 +0000
reviewersbotond
bugs1302493
milestone51.0a1
Bug 1302493 - Update the in-tree APZ documentation to reflect various changes since it was last updated. r?botond MozReview-Commit-ID: 6fzzixDRgUO
gfx/doc/AsyncPanZoom.md
--- a/gfx/doc/AsyncPanZoom.md
+++ b/gfx/doc/AsyncPanZoom.md
@@ -158,57 +158,57 @@ Another problem that we need to deal wit
 This ability is defined in web standards and is non-negotiable.
 Touch event listeners in web content are allowed call preventDefault() on the touchstart or first touchmove event for a touch point; doing this is supposed to "consume" the event and prevent touch-based panning.
 As we saw in a previous section, the input event needs to be untransformed by the APZ code before it can be delivered to content.
 But, because of the preventDefault problem, we cannot fully process the touch event in the APZ code until content has had a chance to handle it.
 Web browsers in general solve this problem by inserting a delay of up to 300ms before processing the input - that is, web content is allowed up to 300ms to process the event and call preventDefault on it.
 If web content takes longer than 300ms, or if it completes handling of the event without calling preventDefault, then the browser immediately starts processing the events.
 
 The way the APZ implementation deals with this is that upon receiving a touch event, it immediately returns an untransformed version that can be dispatched to content.
-It also schedules a 300ms timeout during which content is allowed to prevent scrolling.
+It also schedules a 400ms timeout (600ms on Android) during which content is allowed to prevent scrolling.
 There is an API that allows the main-thread event dispatching code to notify the APZ as to whether or not the default action should be prevented.
 If the APZ content response timeout expires, or if the main-thread event dispatching code notifies the APZ of the preventDefault status, then the APZ continues with the processing of the events (which may involve discarding the events).
 
-The touch-action CSS property from the pointer-events spec is intended to allow eliminating this 300ms delay in many cases (although for backwards compatibility it will still be needed for a while).
+The touch-action CSS property from the pointer-events spec is intended to allow eliminating this 400ms delay in many cases (although for backwards compatibility it will still be needed for a while).
 Note that even with touch-action implemented, there may be cases where the APZ code does not know the touch-action behaviour of the point the user touched.
-In such cases, the APZ code will still wait up to 300ms for the main thread to provide it with the touch-action behaviour information.
+In such cases, the APZ code will still wait up to 400ms for the main thread to provide it with the touch-action behaviour information.
 
 ## Technical details
 
 This section describes various pieces of the APZ code, and goes into more specific detail on APIs and code than the previous sections.
 The primary purpose of this section is to help people who plan on making changes to the code, while also not going into so much detail that it needs to be updated with every patch.
 
 ### Overall flow of input events
 
 This section describes how input events flow through the APZ code.
 <ol>
 <li value="1">
 Input events arrive from the hardware/widget code into the APZ via APZCTreeManager::ReceiveInputEvent.
 The thread that invokes this is called the input thread, and may or may not be the same as the Gecko main thread.
 </li>
 <li value="2">
-Conceptually the first thing that the APZCTreeManager does is to group these events into "input blocks".
-An input block is a contiguous set of events that get handled together.
+Conceptually the first thing that the APZCTreeManager does is to associate these events with "input blocks".
+An input block is a set of events that share certain properties.
 For example with touch events, all events following a touchstart up to but not including the next touchstart are in the same block.
 All of the events in a given block will go to the same APZC instance and will either all be processed or all be dropped.
 </li>
 <li value="3">
 Using the first event in the input block, the APZCTreeManager does a hit-test to see which APZC it hits.
 This hit-test uses the event regions populated on the layers, which may be larger than the true hit area of the layer.
 If no APZC is hit, the events are discarded and we jump to step 6.
 Otherwise, the input block is tagged with the hit APZC as a tentative target and put into a global APZ input queue.
 </li>
 <li value="4">
  <ol>
   <li value="i">
    If the input events landed outside the dispatch-to-content event region for the layer, any available events in the input block are processed.
    These may trigger behaviours like scrolling or tap gestures.
   </li>
   <li value="ii">
-   If the input events landed inside the dispatch-to-content event region for the layer, the events are left in the queue and a 300ms timeout is initiated.
+   If the input events landed inside the dispatch-to-content event region for the layer, the events are left in the queue and a 400ms timeout is initiated.
    If the timeout expires before step 9 is completed, the APZ assumes the input block was not cancelled and the tentative target is correct, and processes them as part of step 10.
   </li>
  </ol>
 </li>
 <li value="5">
 The call stack unwinds back to APZCTreeManager::ReceiveInputEvent, which does an in-place modification of the input event so that any async transforms are removed.
 </li>
 <li value="6">
@@ -218,60 +218,60 @@ This code now has the event in the coord
 <li value="7">
 Gecko performs its own usual hit-testing and event dispatching for the event.
 As part of this, it records whether any touch listeners cancelled the input block by calling preventDefault().
 It also activates inactive scrollframes that were hit by the input events.
 </li>
 <li value="8">
 The call stack unwinds back to the widget code, which sends two notifications to the APZ code on the input thread.
 The first notification is via APZCTreeManager::ContentReceivedInputBlock, and informs the APZ whether the input block was cancelled.
-The second notification is via APZCTreeManager::SetTargetAPZC, and informs the APZ the results of the Gecko hit-test during event dispatch.
+The second notification is via APZCTreeManager::SetTargetAPZC, and informs the APZ of the results of the Gecko hit-test during event dispatch.
 Note that Gecko may report that the input event did not hit any scrollable frame at all.
-These notifications happen only once per input block.
+The SetTargetAPZC notification happens only once per input block, while the ContentReceivedInputBlock notification may happen once per block, or multiple times per block, depending on the input type.
 </li>
 <li value="9">
  <ol>
   <li value="i">
    If the events were processed as part of step 4(i), the notifications from step 8 are ignored and step 10 is skipped.
   </li>
   <li value="ii">
-   If events were queued as part of step 4(ii), and steps 5-8 take less than 300ms, the arrival of both notifications from step 8 will mark the input block ready for processing.
+   If events were queued as part of step 4(ii), and steps 5-8 take less than 400ms, the arrival of both notifications from step 8 will mark the input block ready for processing.
   </li>
   <li value="iii">
-   If events were queued as part of step 4(ii), but steps 5-8 take longer than 300ms, the notifications from step 8 will be ignored and step 10 will already have happened.
+   If events were queued as part of step 4(ii), but steps 5-8 take longer than 400ms, the notifications from step 8 will be ignored and step 10 will already have happened.
   </li>
  </ol>
 </li>
 <li value="10">
 If events were queued as part of step 4(ii) they are now either processed (if the input block was not cancelled and Gecko detected a scrollframe under the input event, or if the timeout expired) or dropped (all other cases).
 Note that the APZC that processes the events may be different at this step than the tentative target from step 3, depending on the SetTargetAPZC notification.
 Processing the events may trigger behaviours like scrolling or tap gestures.
 </li>
 </ol>
 
 If the CSS touch-action property is enabled, the above steps are modified as follows:
 <ul>
 <li>
- In step 4, the APZC also requires the allowed touch-action behaviours for the input event. This is not available yet, so the events are always queued.
+ In step 4, the APZC also requires the allowed touch-action behaviours for the input event.
+ This might have been determined as part of the hit-test in APZCTreeManager; if not, the events are queued.
 </li>
 <li>
  In step 6, the widget code determines the content element at the point under the input element, and notifies the APZ code of the allowed touch-action behaviours.
  This notification is sent via a call to APZCTreeManager::SetAllowedTouchBehavior on the input thread.
 </li>
 <li>
  In step 9(ii), the input block will only be marked ready for processing once all three notifications arrive.
 </li>
 </ul>
 
 #### Threading considerations
 
 The bulk of the input processing in the APZ code happens on what we call "the input thread".
 In practice the input thread could be the Gecko main thread, the compositor thread, or some other thread.
 There are obvious downsides to using the Gecko main thread - that is, "asynchronous" panning and zooming is not really asynchronous as input events can only be processed while Gecko is idle.
-However, this is the current state of things on B2G.
 Using the compositor thread as the input thread could work on some platforms, but may be inefficient on others.
 For example, on Android (Fennec) we receive input events from the system on a dedicated UI thread.
 We would have to redispatch the input events to the compositor thread if we wanted to the input thread to be the same as the compositor thread.
 This introduces a potential for higher latency, particularly if the compositor does any blocking operations - blocking SwapBuffers operations, for example.
 As a result, the APZ code itself does not assume that the input thread will be the same as the Gecko main thread or the compositor thread.
 
 #### Active vs. inactive scrollframes
 
@@ -284,15 +284,15 @@ Consider a page with a scrollframe that 
 When layout generates the layers for this page, the content of the scrollframe will be flattened into some other PaintedLayer (call it P).
 The layout code also adds the area (or bounding region in case of weird shapes) of the scrollframe to the dispatch-to-content region of P.
 
 When the user starts interacting with that content, the hit-test in the APZ code finds the dispatch-to-content region of P.
 The input block therefore has a tentative target of P when it goes into step 4(ii) in the flow above.
 When gecko processes the input event, it must detect the inactive scrollframe and activate it, as part of step 7.
 Finally, the widget code sends the SetTargetAPZC notification in step 8 to notify the APZ that the input block should really apply to this new layer.
 The issue here is that the layer transaction containing the new layer must reach the compositor and APZ before the SetTargetAPZC notification.
-If this does not occur within the 300ms timeout, the APZ code will be unable to update the tentative target, and will continue to use P for that input block.
+If this does not occur within the 400ms timeout, the APZ code will be unable to update the tentative target, and will continue to use P for that input block.
 Input blocks that start after the layer transaction will get correctly routed to the new layer as there will now be a layer and APZC instance for the active scrollframe.
 
 This model implies that when the user initially attempts to scroll an inactive scrollframe, it may end up scrolling an ancestor scrollframe.
 (This is because in the absence of the SetTargetAPZC notification, the input events will get applied to the closest ancestor scrollframe's APZC.)
 Only after the round-trip to the gecko thread is complete is there a layer for async scrolling to actually occur on the scrollframe itself.
 At that point the scrollframe will start receiving new input blocks and will scroll normally.