Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 package org.mozilla.gecko.gfx;
8 import org.mozilla.gecko.GeckoAppShell;
9 import org.mozilla.gecko.GeckoEvent;
10 import org.mozilla.gecko.EventDispatcher;
11 import org.mozilla.gecko.util.GeckoEventListener;
13 import org.json.JSONException;
14 import org.json.JSONObject;
16 import android.graphics.PointF;
17 import android.os.Handler;
18 import android.util.Log;
20 class SubdocumentScrollHelper implements GeckoEventListener {
21 private static final String LOGTAG = "GeckoSubdocScroll";
23 private static String MESSAGE_PANNING_OVERRIDE = "Panning:Override";
24 private static String MESSAGE_CANCEL_OVERRIDE = "Panning:CancelOverride";
25 private static String MESSAGE_SCROLL = "Gesture:Scroll";
26 private static String MESSAGE_SCROLL_ACK = "Gesture:ScrollAck";
28 private final Handler mUiHandler;
29 private final EventDispatcher mEventDispatcher;
31 /* This is the amount of displacement we have accepted but not yet sent to JS; this is
32 * only valid when mOverrideScrollPending is true. */
33 private final PointF mPendingDisplacement;
35 /* When this is true, we're sending scroll events to JS to scroll the active subdocument. */
36 private boolean mOverridePanning;
38 /* When this is true, we have received an ack for the last scroll event we sent to JS, and
39 * are ready to send the next scroll event. Note we only ever have one scroll event inflight
40 * at a time. */
41 private boolean mOverrideScrollAck;
43 /* When this is true, we have a pending scroll that we need to send to JS; we were unable
44 * to send it when it was initially requested because mOverrideScrollAck was not true. */
45 private boolean mOverrideScrollPending;
47 /* When this is true, the last scroll event we sent actually did some amount of scrolling on
48 * the subdocument; we use this to decide when we have reached the end of the subdocument. */
49 private boolean mScrollSucceeded;
51 SubdocumentScrollHelper(EventDispatcher eventDispatcher) {
52 // mUiHandler will be bound to the UI thread since that's where this constructor runs
53 mUiHandler = new Handler();
54 mPendingDisplacement = new PointF();
56 mEventDispatcher = eventDispatcher;
57 registerEventListener(MESSAGE_PANNING_OVERRIDE);
58 registerEventListener(MESSAGE_CANCEL_OVERRIDE);
59 registerEventListener(MESSAGE_SCROLL_ACK);
60 }
62 void destroy() {
63 unregisterEventListener(MESSAGE_PANNING_OVERRIDE);
64 unregisterEventListener(MESSAGE_CANCEL_OVERRIDE);
65 unregisterEventListener(MESSAGE_SCROLL_ACK);
66 }
68 private void registerEventListener(String event) {
69 mEventDispatcher.registerEventListener(event, this);
70 }
72 private void unregisterEventListener(String event) {
73 mEventDispatcher.unregisterEventListener(event, this);
74 }
76 boolean scrollBy(PointF displacement) {
77 if (! mOverridePanning) {
78 return false;
79 }
81 if (! mOverrideScrollAck) {
82 mOverrideScrollPending = true;
83 mPendingDisplacement.x += displacement.x;
84 mPendingDisplacement.y += displacement.y;
85 return true;
86 }
88 JSONObject json = new JSONObject();
89 try {
90 json.put("x", displacement.x);
91 json.put("y", displacement.y);
92 } catch (JSONException e) {
93 Log.e(LOGTAG, "Error forming subwindow scroll message: ", e);
94 }
95 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(MESSAGE_SCROLL, json.toString()));
97 mOverrideScrollAck = false;
98 mOverrideScrollPending = false;
99 // clear the |mPendingDisplacement| after serializing |displacement| to
100 // JSON because they might be the same object
101 mPendingDisplacement.x = 0;
102 mPendingDisplacement.y = 0;
104 return true;
105 }
107 void cancel() {
108 mOverridePanning = false;
109 }
111 boolean scrolling() {
112 return mOverridePanning;
113 }
115 boolean lastScrollSucceeded() {
116 return mScrollSucceeded;
117 }
119 // GeckoEventListener implementation
121 @Override
122 public void handleMessage(final String event, final JSONObject message) {
123 // This comes in on the Gecko thread; hand off the handling to the UI thread.
124 mUiHandler.post(new Runnable() {
125 @Override
126 public void run() {
127 try {
128 if (MESSAGE_PANNING_OVERRIDE.equals(event)) {
129 mOverridePanning = true;
130 mOverrideScrollAck = true;
131 mOverrideScrollPending = false;
132 mScrollSucceeded = true;
133 } else if (MESSAGE_CANCEL_OVERRIDE.equals(event)) {
134 mOverridePanning = false;
135 } else if (MESSAGE_SCROLL_ACK.equals(event)) {
136 mOverrideScrollAck = true;
137 mScrollSucceeded = message.getBoolean("scrolled");
138 if (mOverridePanning && mOverrideScrollPending) {
139 scrollBy(mPendingDisplacement);
140 }
141 }
142 } catch (Exception e) {
143 Log.e(LOGTAG, "Exception handling message", e);
144 }
145 }
146 });
147 }
148 }