michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "APZController.h" michael@0: #include "base/message_loop.h" michael@0: #include "mozilla/layers/GeckoContentController.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "MetroUtils.h" michael@0: #include "nsPrintfCString.h" michael@0: #include "nsIWidgetListener.h" michael@0: #include "mozilla/layers/APZCCallbackHelper.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "nsIDOMWindowUtils.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsLayoutUtils.h" michael@0: #include "mozilla/TouchEvents.h" michael@0: michael@0: //#define DEBUG_CONTROLLER 1 michael@0: michael@0: #ifdef DEBUG_CONTROLLER michael@0: #include "WinUtils.h" michael@0: using namespace mozilla::widget; michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: namespace widget { michael@0: namespace winrt { michael@0: michael@0: nsRefPtr APZController::sAPZC; michael@0: michael@0: /* michael@0: * Metro layout specific - test to see if a sub document is a michael@0: * tab. michael@0: */ michael@0: static bool michael@0: IsTab(nsCOMPtr& aSubDocument) michael@0: { michael@0: nsRefPtr parent = aSubDocument->GetParentDocument(); michael@0: if (!parent) { michael@0: NS_WARNING("huh? IsTab should always get a sub document for a parameter"); michael@0: return false; michael@0: } michael@0: return parent->IsRootDisplayDocument(); michael@0: } michael@0: michael@0: /* michael@0: * Returns the sub document associated with the scroll id. michael@0: */ michael@0: static bool michael@0: GetDOMTargets(uint64_t aScrollId, michael@0: nsCOMPtr& aSubDocument, michael@0: nsCOMPtr& aTargetContent) michael@0: { michael@0: // For tabs and subframes this will return the HTML sub document michael@0: aTargetContent = nsLayoutUtils::FindContentFor(aScrollId); michael@0: if (!aTargetContent) { michael@0: return false; michael@0: } michael@0: nsCOMPtr domElement = do_QueryInterface(aTargetContent); michael@0: if (!domElement) { michael@0: return false; michael@0: } michael@0: michael@0: aSubDocument = domElement->OwnerDoc(); michael@0: michael@0: if (!aSubDocument) { michael@0: return false; michael@0: } michael@0: michael@0: // If the root element equals domElement, FindElementWithViewId found michael@0: // a document, vs. an element within a document. michael@0: if (aSubDocument->GetRootElement() == domElement && IsTab(aSubDocument)) { michael@0: aTargetContent = nullptr; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: class RequestContentRepaintEvent : public nsRunnable michael@0: { michael@0: typedef mozilla::layers::FrameMetrics FrameMetrics; michael@0: michael@0: public: michael@0: RequestContentRepaintEvent(const FrameMetrics& aFrameMetrics, michael@0: nsIWidgetListener* aListener) : michael@0: mFrameMetrics(aFrameMetrics), michael@0: mWidgetListener(aListener) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHOD Run() { michael@0: // This must be on the gecko thread since we access the dom michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: #ifdef DEBUG_CONTROLLER michael@0: WinUtils::Log("APZController: mScrollOffset: %f %f", mFrameMetrics.mScrollOffset.x, michael@0: mFrameMetrics.mScrollOffset.y); michael@0: #endif michael@0: michael@0: nsCOMPtr subDocument; michael@0: nsCOMPtr targetContent; michael@0: if (!GetDOMTargets(mFrameMetrics.GetScrollId(), michael@0: subDocument, targetContent)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // If we're dealing with a sub frame or content editable element, michael@0: // call UpdateSubFrame. michael@0: if (targetContent) { michael@0: #ifdef DEBUG_CONTROLLER michael@0: WinUtils::Log("APZController: detected subframe or content editable"); michael@0: #endif michael@0: mozilla::layers::APZCCallbackHelper::UpdateSubFrame(targetContent, mFrameMetrics); michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef DEBUG_CONTROLLER michael@0: WinUtils::Log("APZController: detected tab"); michael@0: #endif michael@0: michael@0: // We're dealing with a tab, call UpdateRootFrame. michael@0: nsCOMPtr utils; michael@0: nsCOMPtr window = subDocument->GetDefaultView(); michael@0: if (window) { michael@0: utils = do_GetInterface(window); michael@0: if (utils) { michael@0: mozilla::layers::APZCCallbackHelper::UpdateRootFrame(utils, mFrameMetrics); michael@0: michael@0: #ifdef DEBUG_CONTROLLER michael@0: WinUtils::Log("APZController: %I64d mDisplayPortMargins: %0.2f %0.2f %0.2f %0.2f", michael@0: mFrameMetrics.GetScrollId(), michael@0: mFrameMetrics.GetDisplayPortMargins().left, michael@0: mFrameMetrics.GetDisplayPortMargins().top, michael@0: mFrameMetrics.GetDisplayPortMargins().right, michael@0: mFrameMetrics.GetDisplayPortMargins().bottom); michael@0: #endif michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: protected: michael@0: FrameMetrics mFrameMetrics; michael@0: nsIWidgetListener* mWidgetListener; michael@0: }; michael@0: michael@0: void michael@0: APZController::SetWidgetListener(nsIWidgetListener* aWidgetListener) michael@0: { michael@0: mWidgetListener = aWidgetListener; michael@0: } michael@0: michael@0: void michael@0: APZController::ContentReceivedTouch(const ScrollableLayerGuid& aGuid, bool aPreventDefault) michael@0: { michael@0: if (!sAPZC) { michael@0: return; michael@0: } michael@0: sAPZC->ContentReceivedTouch(aGuid, aPreventDefault); michael@0: } michael@0: michael@0: bool michael@0: APZController::HitTestAPZC(ScreenIntPoint& aPoint) michael@0: { michael@0: if (!sAPZC) { michael@0: return false; michael@0: } michael@0: return sAPZC->HitTestAPZC(aPoint); michael@0: } michael@0: michael@0: void michael@0: APZController::TransformCoordinateToGecko(const ScreenIntPoint& aPoint, michael@0: LayoutDeviceIntPoint* aRefPointOut) michael@0: { michael@0: if (!sAPZC || !aRefPointOut) { michael@0: return; michael@0: } michael@0: sAPZC->TransformCoordinateToGecko(aPoint, aRefPointOut); michael@0: } michael@0: michael@0: nsEventStatus michael@0: APZController::ReceiveInputEvent(WidgetInputEvent* aEvent, michael@0: ScrollableLayerGuid* aOutTargetGuid) michael@0: { michael@0: MOZ_ASSERT(aEvent); michael@0: michael@0: if (!sAPZC) { michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: return sAPZC->ReceiveInputEvent(*aEvent->AsInputEvent(), aOutTargetGuid); michael@0: } michael@0: michael@0: // APZC sends us this request when we need to update the display port on michael@0: // the scrollable frame the apzc is managing. michael@0: void michael@0: APZController::RequestContentRepaint(const FrameMetrics& aFrameMetrics) michael@0: { michael@0: if (!mWidgetListener) { michael@0: NS_WARNING("Can't update display port, !mWidgetListener"); michael@0: return; michael@0: } michael@0: michael@0: #ifdef DEBUG_CONTROLLER michael@0: WinUtils::Log("APZController::RequestContentRepaint scrollid=%I64d", michael@0: aFrameMetrics.GetScrollId()); michael@0: #endif michael@0: nsCOMPtr r1 = new RequestContentRepaintEvent(aFrameMetrics, michael@0: mWidgetListener); michael@0: if (!NS_IsMainThread()) { michael@0: NS_DispatchToMainThread(r1); michael@0: } else { michael@0: r1->Run(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: APZController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, michael@0: const uint32_t& aScrollGeneration) michael@0: { michael@0: #ifdef DEBUG_CONTROLLER michael@0: WinUtils::Log("APZController::AcknowledgeScrollUpdate scrollid=%I64d gen=%lu", michael@0: aScrollId, aScrollGeneration); michael@0: #endif michael@0: mozilla::layers::APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration); michael@0: } michael@0: michael@0: void michael@0: APZController::HandleDoubleTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid& aGuid) michael@0: { michael@0: } michael@0: michael@0: void michael@0: APZController::HandleSingleTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid& aGuid) michael@0: { michael@0: } michael@0: michael@0: void michael@0: APZController::HandleLongTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid& aGuid) michael@0: { michael@0: } michael@0: michael@0: void michael@0: APZController::HandleLongTapUp(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid& aGuid) michael@0: { michael@0: } michael@0: michael@0: // requests that we send a mozbrowserasyncscroll domevent. not in use. michael@0: void michael@0: APZController::SendAsyncScrollDOMEvent(bool aIsRoot, michael@0: const CSSRect &aContentRect, michael@0: const CSSSize &aScrollableSize) michael@0: { michael@0: } michael@0: michael@0: void michael@0: APZController::PostDelayedTask(Task* aTask, int aDelayMs) michael@0: { michael@0: MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs); michael@0: } michael@0: michael@0: bool michael@0: APZController::GetRootZoomConstraints(ZoomConstraints* aOutConstraints) michael@0: { michael@0: if (aOutConstraints) { michael@0: // Until we support the meta-viewport tag properly allow zooming michael@0: // from 1/4 to 4x by default. michael@0: aOutConstraints->mAllowZoom = true; michael@0: aOutConstraints->mAllowDoubleTapZoom = false; michael@0: aOutConstraints->mMinZoom = CSSToScreenScale(0.25f); michael@0: aOutConstraints->mMaxZoom = CSSToScreenScale(4.0f); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: // apzc notifications michael@0: michael@0: class TransformedStartEvent : public nsRunnable michael@0: { michael@0: NS_IMETHOD Run() { michael@0: MetroUtils::FireObserver("apzc-transform-start", L""); michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: class TransformedEndEvent : public nsRunnable michael@0: { michael@0: NS_IMETHOD Run() { michael@0: MetroUtils::FireObserver("apzc-transform-end", L""); michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: void michael@0: APZController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid, michael@0: APZStateChange aChange, michael@0: int aArg) michael@0: { michael@0: switch (aChange) { michael@0: case APZStateChange::TransformBegin: michael@0: { michael@0: if (NS_IsMainThread()) { michael@0: MetroUtils::FireObserver("apzc-transform-begin", L""); michael@0: return; michael@0: } michael@0: nsCOMPtr runnable = new TransformedStartEvent(); michael@0: NS_DispatchToMainThread(runnable); michael@0: break; michael@0: } michael@0: case APZStateChange::TransformEnd: michael@0: { michael@0: if (NS_IsMainThread()) { michael@0: MetroUtils::FireObserver("apzc-transform-end", L""); michael@0: return; michael@0: } michael@0: nsCOMPtr runnable = new TransformedEndEvent(); michael@0: NS_DispatchToMainThread(runnable); michael@0: break; michael@0: } michael@0: default: michael@0: { michael@0: // We don't currently care about other state changes. michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: } } }