summaryrefslogtreecommitdiffstats
path: root/widget/android/AndroidContentController.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/android/AndroidContentController.cpp')
-rw-r--r--widget/android/AndroidContentController.cpp157
1 files changed, 157 insertions, 0 deletions
diff --git a/widget/android/AndroidContentController.cpp b/widget/android/AndroidContentController.cpp
new file mode 100644
index 000000000..1df053afb
--- /dev/null
+++ b/widget/android/AndroidContentController.cpp
@@ -0,0 +1,157 @@
+/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AndroidContentController.h"
+
+#include "AndroidBridge.h"
+#include "base/message_loop.h"
+#include "mozilla/layers/APZCCallbackHelper.h"
+#include "mozilla/layers/IAPZCTreeManager.h"
+#include "nsIObserverService.h"
+#include "nsLayoutUtils.h"
+#include "nsWindow.h"
+
+using mozilla::layers::IAPZCTreeManager;
+
+namespace mozilla {
+namespace widget {
+
+void
+AndroidContentController::Destroy()
+{
+ mAndroidWindow = nullptr;
+ ChromeProcessController::Destroy();
+}
+
+void
+AndroidContentController::NotifyDefaultPrevented(IAPZCTreeManager* aManager,
+ uint64_t aInputBlockId,
+ bool aDefaultPrevented)
+{
+ if (!AndroidBridge::IsJavaUiThread()) {
+ // The notification must reach the APZ on the Java UI thread (aka the
+ // APZ "controller" thread) but we get it from the Gecko thread, so we
+ // have to throw it onto the other thread.
+ AndroidBridge::Bridge()->PostTaskToUiThread(NewRunnableMethod<uint64_t, bool>(
+ aManager, &IAPZCTreeManager::ContentReceivedInputBlock,
+ aInputBlockId, aDefaultPrevented), 0);
+ return;
+ }
+
+ aManager->ContentReceivedInputBlock(aInputBlockId, aDefaultPrevented);
+}
+
+void
+AndroidContentController::DispatchSingleTapToObservers(const LayoutDevicePoint& aPoint,
+ const ScrollableLayerGuid& aGuid) const
+{
+ nsIContent* content = nsLayoutUtils::FindContentFor(aGuid.mScrollId);
+ nsPresContext* context = content
+ ? mozilla::layers::APZCCallbackHelper::GetPresContextForContent(content)
+ : nullptr;
+
+ if (!context) {
+ return;
+ }
+
+ CSSPoint point = mozilla::layers::APZCCallbackHelper::ApplyCallbackTransform(
+ aPoint / context->CSSToDevPixelScale(), aGuid);
+
+ nsPresContext* rcdContext = context->GetToplevelContentDocumentPresContext();
+ if (rcdContext && rcdContext->PresShell()->ScaleToResolution()) {
+ // We need to convert from the root document to the root content document,
+ // by unapplying the resolution that's on the content document.
+ const float resolution = rcdContext->PresShell()->GetResolution();
+ point.x /= resolution;
+ point.y /= resolution;
+ }
+
+ CSSIntPoint rounded = RoundedToInt(point);
+ nsAppShell::PostEvent([rounded] {
+ nsCOMPtr<nsIObserverService> obsServ =
+ mozilla::services::GetObserverService();
+ if (!obsServ) {
+ return;
+ }
+
+ nsPrintfCString data("{\"x\":%d,\"y\":%d}", rounded.x, rounded.y);
+ obsServ->NotifyObservers(nullptr, "Gesture:SingleTap",
+ NS_ConvertASCIItoUTF16(data).get());
+ });
+}
+
+void
+AndroidContentController::HandleTap(TapType aType, const LayoutDevicePoint& aPoint,
+ Modifiers aModifiers,
+ const ScrollableLayerGuid& aGuid,
+ uint64_t aInputBlockId)
+{
+ // This function will get invoked first on the Java UI thread, and then
+ // again on the main thread (because of the code in ChromeProcessController::
+ // HandleTap). We want to post the SingleTap message once; it can be
+ // done from either thread but we need access to the callback transform
+ // so we do it from the main thread.
+ if (NS_IsMainThread() &&
+ (aType == TapType::eSingleTap || aType == TapType::eSecondTap)) {
+ DispatchSingleTapToObservers(aPoint, aGuid);
+ }
+
+ ChromeProcessController::HandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId);
+}
+
+void
+AndroidContentController::PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
+{
+ AndroidBridge::Bridge()->PostTaskToUiThread(Move(aTask), aDelayMs);
+}
+void
+AndroidContentController::UpdateOverscrollVelocity(const float aX, const float aY, const bool aIsRootContent)
+{
+ if (aIsRootContent && mAndroidWindow) {
+ mAndroidWindow->UpdateOverscrollVelocity(aX, aY);
+ }
+}
+
+void
+AndroidContentController::UpdateOverscrollOffset(const float aX, const float aY, const bool aIsRootContent)
+{
+ if (aIsRootContent && mAndroidWindow) {
+ mAndroidWindow->UpdateOverscrollOffset(aX, aY);
+ }
+}
+
+void
+AndroidContentController::SetScrollingRootContent(const bool isRootContent)
+{
+ if (mAndroidWindow) {
+ mAndroidWindow->SetScrollingRootContent(isRootContent);
+ }
+}
+
+void
+AndroidContentController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
+ APZStateChange aChange,
+ int aArg)
+{
+ // This function may get invoked twice, if the first invocation is not on
+ // the main thread then the ChromeProcessController version of this function
+ // will redispatch to the main thread. We want to make sure that our handling
+ // only happens on the main thread.
+ ChromeProcessController::NotifyAPZStateChange(aGuid, aChange, aArg);
+ if (NS_IsMainThread()) {
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
+ if (aChange == layers::GeckoContentController::APZStateChange::eTransformEnd) {
+ // This is used by tests to determine when the APZ is done doing whatever
+ // it's doing. XXX generify this as needed when writing additional tests.
+ observerService->NotifyObservers(nullptr, "APZ:TransformEnd", nullptr);
+ observerService->NotifyObservers(nullptr, "PanZoom:StateChange", u"NOTHING");
+ } else if (aChange == layers::GeckoContentController::APZStateChange::eTransformBegin) {
+ observerService->NotifyObservers(nullptr, "PanZoom:StateChange", u"PANNING");
+ }
+ }
+}
+
+} // namespace widget
+} // namespace mozilla