diff options
Diffstat (limited to 'gfx/layers/apz/util/ChromeProcessController.cpp')
-rw-r--r-- | gfx/layers/apz/util/ChromeProcessController.cpp | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/gfx/layers/apz/util/ChromeProcessController.cpp b/gfx/layers/apz/util/ChromeProcessController.cpp new file mode 100644 index 000000000..ac8b3824f --- /dev/null +++ b/gfx/layers/apz/util/ChromeProcessController.cpp @@ -0,0 +1,276 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "ChromeProcessController.h" + +#include "MainThreadUtils.h" // for NS_IsMainThread() +#include "base/message_loop.h" // for MessageLoop +#include "mozilla/dom/Element.h" +#include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/APZCCallbackHelper.h" +#include "mozilla/layers/APZEventState.h" +#include "mozilla/layers/IAPZCTreeManager.h" +#include "mozilla/layers/DoubleTapToZoom.h" +#include "nsIDocument.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIPresShell.h" +#include "nsLayoutUtils.h" +#include "nsView.h" + +using namespace mozilla; +using namespace mozilla::layers; +using namespace mozilla::widget; + +ChromeProcessController::ChromeProcessController(nsIWidget* aWidget, + APZEventState* aAPZEventState, + IAPZCTreeManager* aAPZCTreeManager) + : mWidget(aWidget) + , mAPZEventState(aAPZEventState) + , mAPZCTreeManager(aAPZCTreeManager) + , mUILoop(MessageLoop::current()) +{ + // Otherwise we're initializing mUILoop incorrectly. + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aAPZEventState); + MOZ_ASSERT(aAPZCTreeManager); + + mUILoop->PostTask(NewRunnableMethod(this, &ChromeProcessController::InitializeRoot)); +} + +ChromeProcessController::~ChromeProcessController() {} + +void +ChromeProcessController::InitializeRoot() +{ + APZCCallbackHelper::InitializeRootDisplayport(GetPresShell()); +} + +void +ChromeProcessController::RequestContentRepaint(const FrameMetrics& aFrameMetrics) +{ + MOZ_ASSERT(IsRepaintThread()); + + FrameMetrics metrics = aFrameMetrics; + if (metrics.IsRootContent()) { + APZCCallbackHelper::UpdateRootFrame(metrics); + } else { + APZCCallbackHelper::UpdateSubFrame(metrics); + } +} + +void +ChromeProcessController::PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) +{ + MessageLoop::current()->PostDelayedTask(Move(aTask), aDelayMs); +} + +bool +ChromeProcessController::IsRepaintThread() +{ + return NS_IsMainThread(); +} + +void +ChromeProcessController::DispatchToRepaintThread(already_AddRefed<Runnable> aTask) +{ + NS_DispatchToMainThread(Move(aTask)); +} + +void +ChromeProcessController::Destroy() +{ + if (MessageLoop::current() != mUILoop) { + mUILoop->PostTask(NewRunnableMethod(this, &ChromeProcessController::Destroy)); + return; + } + + MOZ_ASSERT(MessageLoop::current() == mUILoop); + mWidget = nullptr; + mAPZEventState = nullptr; +} + +nsIPresShell* +ChromeProcessController::GetPresShell() const +{ + if (!mWidget) { + return nullptr; + } + if (nsView* view = nsView::GetViewFor(mWidget)) { + return view->GetPresShell(); + } + return nullptr; +} + +nsIDocument* +ChromeProcessController::GetRootDocument() const +{ + if (nsIPresShell* presShell = GetPresShell()) { + return presShell->GetDocument(); + } + return nullptr; +} + +nsIDocument* +ChromeProcessController::GetRootContentDocument(const FrameMetrics::ViewID& aScrollId) const +{ + nsIContent* content = nsLayoutUtils::FindContentFor(aScrollId); + if (!content) { + return nullptr; + } + nsIPresShell* presShell = APZCCallbackHelper::GetRootContentDocumentPresShellForContent(content); + if (presShell) { + return presShell->GetDocument(); + } + return nullptr; +} + +void +ChromeProcessController::HandleDoubleTap(const mozilla::CSSPoint& aPoint, + Modifiers aModifiers, + const ScrollableLayerGuid& aGuid) +{ + MOZ_ASSERT(MessageLoop::current() == mUILoop); + + nsCOMPtr<nsIDocument> document = GetRootContentDocument(aGuid.mScrollId); + if (!document.get()) { + return; + } + + // CalculateRectToZoomTo performs a hit test on the frame associated with the + // Root Content Document. Unfortunately that frame does not know about the + // resolution of the document and so we must remove it before calculating + // the zoomToRect. + nsIPresShell* presShell = document->GetShell(); + const float resolution = presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f; + CSSPoint point(aPoint.x / resolution, aPoint.y / resolution); + CSSRect zoomToRect = CalculateRectToZoomTo(document, point); + + uint32_t presShellId; + FrameMetrics::ViewID viewId; + if (APZCCallbackHelper::GetOrCreateScrollIdentifiers( + document->GetDocumentElement(), &presShellId, &viewId)) { + mAPZCTreeManager->ZoomToRect( + ScrollableLayerGuid(aGuid.mLayersId, presShellId, viewId), zoomToRect); + } +} + +void +ChromeProcessController::HandleTap(TapType aType, + const mozilla::LayoutDevicePoint& aPoint, + Modifiers aModifiers, + const ScrollableLayerGuid& aGuid, + uint64_t aInputBlockId) +{ + if (MessageLoop::current() != mUILoop) { + mUILoop->PostTask(NewRunnableMethod<TapType, mozilla::LayoutDevicePoint, Modifiers, + ScrollableLayerGuid, uint64_t>(this, + &ChromeProcessController::HandleTap, + aType, aPoint, aModifiers, aGuid, aInputBlockId)); + return; + } + + if (!mAPZEventState) { + return; + } + + nsCOMPtr<nsIPresShell> presShell = GetPresShell(); + if (!presShell) { + return; + } + if (!presShell->GetPresContext()) { + return; + } + CSSToLayoutDeviceScale scale(presShell->GetPresContext()->CSSToDevPixelScale()); + CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint / scale, aGuid); + + switch (aType) { + case TapType::eSingleTap: + mAPZEventState->ProcessSingleTap(point, scale, aModifiers, aGuid, 1); + break; + case TapType::eDoubleTap: + HandleDoubleTap(point, aModifiers, aGuid); + break; + case TapType::eSecondTap: + mAPZEventState->ProcessSingleTap(point, scale, aModifiers, aGuid, 2); + break; + case TapType::eLongTap: + mAPZEventState->ProcessLongTap(presShell, point, scale, aModifiers, aGuid, + aInputBlockId); + break; + case TapType::eLongTapUp: + mAPZEventState->ProcessLongTapUp(presShell, point, scale, aModifiers); + break; + case TapType::eSentinel: + // Should never happen, but we need to handle this case branch for the + // compiler to be happy. + MOZ_ASSERT(false); + break; + } +} + +void +ChromeProcessController::NotifyPinchGesture(PinchGestureInput::PinchGestureType aType, + const ScrollableLayerGuid& aGuid, + LayoutDeviceCoord aSpanChange, + Modifiers aModifiers) +{ + if (MessageLoop::current() != mUILoop) { + mUILoop->PostTask(NewRunnableMethod + <PinchGestureInput::PinchGestureType, + ScrollableLayerGuid, + LayoutDeviceCoord, + Modifiers>(this, + &ChromeProcessController::NotifyPinchGesture, + aType, aGuid, aSpanChange, aModifiers)); + return; + } + + if (mWidget) { + APZCCallbackHelper::NotifyPinchGesture(aType, aSpanChange, aModifiers, mWidget.get()); + } +} + +void +ChromeProcessController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid, + APZStateChange aChange, + int aArg) +{ + if (MessageLoop::current() != mUILoop) { + mUILoop->PostTask(NewRunnableMethod + <ScrollableLayerGuid, + APZStateChange, + int>(this, &ChromeProcessController::NotifyAPZStateChange, + aGuid, aChange, aArg)); + return; + } + + if (!mAPZEventState) { + return; + } + + mAPZEventState->ProcessAPZStateChange(aGuid.mScrollId, aChange, aArg); +} + +void +ChromeProcessController::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent) +{ + if (MessageLoop::current() != mUILoop) { + mUILoop->PostTask(NewRunnableMethod + <FrameMetrics::ViewID, + nsString>(this, &ChromeProcessController::NotifyMozMouseScrollEvent, + aScrollId, aEvent)); + return; + } + + APZCCallbackHelper::NotifyMozMouseScrollEvent(aScrollId, aEvent); +} + +void +ChromeProcessController::NotifyFlushComplete() +{ + MOZ_ASSERT(IsRepaintThread()); + + APZCCallbackHelper::NotifyFlushComplete(GetPresShell()); +} |