Backed out 4 changesets (bug 1633322) for android failures e.g. test_group_checkerboarding.html. CLOSED TREE

Backed out changeset ffa257a29649 (bug 1633322)
Backed out changeset 8271d4e51f25 (bug 1633322)
Backed out changeset 21c0baa65724 (bug 1633322)
Backed out changeset 193fa2a0b926 (bug 1633322)
This commit is contained in:
Csoregi Natalia 2020-08-18 23:45:49 +03:00
parent ff0a68004d
commit 15818e2195
19 changed files with 144 additions and 391 deletions

View File

@ -53,25 +53,30 @@ struct APZEventResult {
*/
nsEventStatus mStatus;
/**
* The guid of the APZC initially targeted by this event.
* This will usually be the APZC that handles the event, but in cases
* where the event is dispatched to content, it may end up being
* handled by a different APZC.
* The guid of the APZC this event was delivered to.
*/
ScrollableLayerGuid mTargetGuid;
/**
* This is:
* - set to true if we know for sure that the event will be handled
* by the root content APZC;
* - set to false if we know for sure it will not be;
* - left empty if we are unsure.
* Whether or not mTargetGuid refers to the root content APZC. This gets set
* to false in cases where APZ is unsure due to imprecision in hit-testing.
*/
Maybe<bool> mHandledByRootApzc;
bool mTargetIsRoot;
/**
* If this event started or was added to an input block, the id of that
* input block, otherwise InputBlockState::NO_BLOCK_ID.
*/
uint64_t mInputBlockId;
/**
* True if the event is targeting a region with non-passive APZ-aware
* listeners, that is, a region where we need to dispatch the event to Gecko
* to see if a listener will prevent-default it.
* Notes:
* 1) This is currently only set for touch events.
* 2) For non-WebRender, this will have some false positives; it will
* be set in some cases where we need to dispatch the event to Gecko
* before handling for other reasons than APZ-aware listeners.
*/
bool mHitRegionWithApzAwareListeners;
};
/**

View File

@ -131,27 +131,6 @@ class IAPZCTreeManager {
*/
virtual APZInputBridge* InputBridge() = 0;
/**
* Add a callback to be invoked when |aInputBlockId| is ready for handling,
* with a boolean indicating whether the APZC handling the input block is
* the root content APZC.
*
* Should only be used for input blocks that are not yet ready for handling
* at the time this is called. If the input block was already handled,
* the callback will never be called.
*
* Only one callback can be registered for an input block at a time.
* Subsequent attempts to register a callback for an input block will be
* ignored until the existing callback is triggered.
*
* This is only implemented when the caller is in the same process as
* the APZCTreeManager.
*/
using InputBlockCallback =
std::function<void(uint64_t aInputBlockId, bool aHandledByRootApzc)>;
virtual void AddInputBlockCallback(uint64_t aInputBlockId,
InputBlockCallback&& aCallback) = 0;
protected:
// Discourage destruction outside of decref

View File

@ -1540,7 +1540,7 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
// Update the out-parameters so they are what the caller expects.
hit.mTargetApzc->GetGuid(&result.mTargetGuid);
result.mHandledByRootApzc = hit.HandledByRoot();
result.mTargetIsRoot = hit.TargetIsConfirmedRoot();
if (!hitScrollbar) {
// The input was not targeted at a scrollbar, so we untransform it
@ -1625,7 +1625,7 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
// Update the out-parameters so they are what the caller expects.
hit.mTargetApzc->GetGuid(&result.mTargetGuid);
result.mHandledByRootApzc = hit.HandledByRoot();
result.mTargetIsRoot = hit.TargetIsConfirmedRoot();
wheelInput.mOrigin = *untransformedOrigin;
}
break;
@ -1684,7 +1684,7 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
// Update the out-parameters so they are what the caller expects.
hit.mTargetApzc->GetGuid(&result.mTargetGuid);
result.mHandledByRootApzc = hit.HandledByRoot();
result.mTargetIsRoot = hit.TargetIsConfirmedRoot();
panInput.mPanStartPoint = *untransformedStartPoint;
panInput.mPanDisplacement = *untransformedDisplacement;
@ -1733,7 +1733,7 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
// Update the out-parameters so they are what the caller expects.
hit.mTargetApzc->GetGuid(&result.mTargetGuid);
result.mHandledByRootApzc = hit.HandledByRoot();
result.mTargetIsRoot = hit.TargetIsConfirmedRoot();
pinchInput.mFocusPoint = *untransformedFocusPoint;
}
break;
@ -1763,7 +1763,7 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
// Update the out-parameters so they are what the caller expects.
hit.mTargetApzc->GetGuid(&result.mTargetGuid);
result.mHandledByRootApzc = hit.HandledByRoot();
result.mTargetIsRoot = hit.TargetIsConfirmedRoot();
tapInput.mPoint = *untransformedPoint;
}
break;
@ -1935,6 +1935,21 @@ APZCTreeManager::HitTestResult APZCTreeManager::GetTouchInputBlockAPZC(
return hit;
}
/**
* Returns whether |aHitResult| *may* indicate that we hit a region with
* APZ-aware listeners.
*/
bool MayHaveApzAwareListeners(CompositorHitTestInfo aHitResult) {
// With WebRender, we can answer this accurately.
if (gfx::gfxVars::UseWebRender()) {
return aHitResult.contains(CompositorHitTestFlags::eApzAwareListeners);
}
// With non-WebRender, several hit results including eApzAwareListeners
// get lumped together into the dispatch-to-content region. We err on
// the side of false positives.
return !((aHitResult & CompositorHitTestDispatchToContent).isEmpty());
}
APZEventResult APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput) {
APZEventResult result; // mStatus == eIgnore
aInput.mHandledByAPZ = true;
@ -2034,13 +2049,15 @@ APZEventResult APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput) {
CompositorHitTestInvisibleToHit);
mTouchBlockHitResult.mTargetApzc->GetGuid(&result.mTargetGuid);
result.mHandledByRootApzc = mTouchBlockHitResult.HandledByRoot();
result.mTargetIsRoot = mTouchBlockHitResult.TargetIsConfirmedRoot();
result.mStatus = mInputQueue->ReceiveInputEvent(
mTouchBlockHitResult.mTargetApzc,
TargetConfirmationFlags{mTouchBlockHitResult.mHitResult}, aInput,
&result.mInputBlockId,
touchBehaviors.IsEmpty() ? Nothing()
: Some(std::move(touchBehaviors)));
result.mHitRegionWithApzAwareListeners =
MayHaveApzAwareListeners(mTouchBlockHitResult.mHitResult);
// For computing the event to pass back to Gecko, use up-to-date
// transforms (i.e. not anything cached in an input block). This ensures
@ -2137,7 +2154,7 @@ APZEventResult APZCTreeManager::ProcessTouchInputForScrollbarDrag(
}
mTouchBlockHitResult.mTargetApzc->GetGuid(&result.mTargetGuid);
result.mHandledByRootApzc = mTouchBlockHitResult.HandledByRoot();
result.mTargetIsRoot = mTouchBlockHitResult.TargetIsConfirmedRoot();
// Since the input was targeted at a scrollbar:
// - The original touch event (which will be sent on to content) will
@ -2949,11 +2966,6 @@ void APZCTreeManager::SetLongTapEnabled(bool aLongTapEnabled) {
GestureEventListener::SetLongTapEnabled(aLongTapEnabled);
}
void APZCTreeManager::AddInputBlockCallback(uint64_t aInputBlockId,
InputBlockCallback&& aCallback) {
mInputQueue->AddInputBlockCallback(aInputBlockId, std::move(aCallback));
}
void APZCTreeManager::FindScrollThumbNode(
const AsyncDragMetrics& aDragMetrics,
HitTestingTreeNodeAutoLock& aOutThumbNode) {
@ -3944,19 +3956,12 @@ APZCTreeManager::StickyPositionInfo::StickyPositionInfo(
mStickyScrollRangeOuter = aNode->GetStickyScrollRangeOuter();
}
Maybe<bool> APZCTreeManager::HitTestResult::HandledByRoot() const {
if (!mTargetApzc->IsRootContent()) {
// If the initial target is not the root, this will definitely not be
// handled by the root. (The confirmed target is either the initial
// target, or a descendant.)
return Some(false);
} else if ((mHitResult & CompositorHitTestDispatchToContent).isEmpty()) {
// If the initial target is the root and we don't need to dispatch to
// content, the event will definitely be handled by the root.
return Some(true);
}
// Otherwise, we're not sure.
return Nothing();
bool APZCTreeManager::HitTestResult::TargetIsConfirmedRoot() const {
CompositorHitTestInfo impreciseHitAreaFlags(
CompositorHitTestFlags::eIrregularArea,
CompositorHitTestFlags::eInactiveScrollframe);
return (mHitResult & impreciseHitAreaFlags).isEmpty() &&
mTargetApzc->IsRootContent();
}
} // namespace layers

View File

@ -424,9 +424,6 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
APZInputBridge* InputBridge() override { return this; }
void AddInputBlockCallback(uint64_t aInputBlockId,
InputBlockCallback&& aCallback) override;
// Methods to help process WidgetInputEvents (or manage conversion to/from
// InputData)
@ -560,7 +557,7 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
// Make it move-only.
HitTestResult(HitTestResult&&) = default;
HitTestResult& operator=(HitTestResult&&) = default;
Maybe<bool> HandledByRoot() const;
bool TargetIsConfirmedRoot() const;
};
/* Some helper functions to find an APZC given some identifying input. These

View File

@ -25,7 +25,9 @@ namespace layers {
APZEventResult::APZEventResult()
: mStatus(nsEventStatus_eIgnore),
mInputBlockId(InputBlockState::NO_BLOCK_ID) {}
mTargetIsRoot(false),
mInputBlockId(InputBlockState::NO_BLOCK_ID),
mHitRegionWithApzAwareListeners(false) {}
static bool WillHandleMouseEvent(const WidgetMouseEventBase& aEvent) {
return aEvent.mMessage == eMouseMove || aEvent.mMessage == eMouseDown ||

View File

@ -640,12 +640,6 @@ InputBlockState* InputQueue::GetBlockForId(uint64_t aInputBlockId) {
return FindBlockForId(aInputBlockId, nullptr);
}
void InputQueue::AddInputBlockCallback(uint64_t aInputBlockId,
InputBlockCallback&& aCallback) {
mInputBlockCallbacks.insert(
InputBlockCallbackMap::value_type(aInputBlockId, std::move(aCallback)));
}
InputBlockState* InputQueue::FindBlockForId(uint64_t aInputBlockId,
InputData** aOutFirstInput) {
for (const auto& queuedInput : mQueuedInputs) {
@ -827,18 +821,6 @@ void InputQueue::ProcessQueue() {
curBlock, cancelable && cancelable->IsDefaultPrevented(),
curBlock->ShouldDropEvents(), curBlock->GetTargetApzc().get());
RefPtr<AsyncPanZoomController> target = curBlock->GetTargetApzc();
// If there is an input block callback registered for this
// input block, invoke it.
auto it = mInputBlockCallbacks.find(curBlock->GetBlockId());
if (it != mInputBlockCallbacks.end()) {
bool handledByRootApzc =
!curBlock->ShouldDropEvents() && target && target->IsRootContent();
it->second(curBlock->GetBlockId(), handledByRootApzc);
// The callback is one-shot; discard it after calling it.
mInputBlockCallbacks.erase(it);
}
// target may be null here if the initial target was unconfirmed and then
// we later got a confirmed null target. in that case drop the events.
if (target) {

View File

@ -16,8 +16,6 @@
#include "mozilla/UniquePtr.h"
#include "nsTArray.h"
#include <unordered_map>
namespace mozilla {
class InputData;
@ -146,11 +144,6 @@ class InputQueue {
InputBlockState* GetBlockForId(uint64_t aInputBlockId);
using InputBlockCallback =
std::function<void(uint64_t aInputBlockId, bool aHandledByRootApzc)>;
void AddInputBlockCallback(uint64_t aInputBlockId,
InputBlockCallback&& aCallback);
private:
~InputQueue();
@ -255,12 +248,6 @@ class InputQueue {
// Temporarily stores a timeout task that needs to be run as soon as
// as the event that triggered it has been queued.
RefPtr<Runnable> mImmediateTimeout;
// Maps input block ids to callbacks that will be invoked when the input block
// is ready for handling.
using InputBlockCallbackMap =
std::unordered_map<uint64_t, InputBlockCallback>;
InputBlockCallbackMap mInputBlockCallbacks;
};
} // namespace layers

View File

@ -7,7 +7,6 @@
#include "APZCTreeManagerTester.h"
#include "APZTestCommon.h"
#include "InputUtils.h"
#include "mozilla/layers/LayersTypes.h"
class APZEventRegionsTester : public APZCTreeManagerTester {
protected:
@ -311,9 +310,9 @@ TEST_F(APZEventRegionsTester, Bug1117712) {
manager->SetTargetAPZC(inputBlockId, targets);
}
// Test that APZEventResult::mHandledByRootApzc is correctly
// Test that APZEventResult::mHitRegionWithApzAwareListeners is correctly
// populated.
TEST_F(APZEventRegionsTester, HandledByRootApzcFlag) {
TEST_F(APZEventRegionsTester, ApzAwareListenersFlag) {
// Create simple layer tree containing a dispatch-to-content region
// that covers part but not all of its area.
const char* layerTreeSyntax = "c";
@ -323,8 +322,6 @@ TEST_F(APZEventRegionsTester, HandledByRootApzcFlag) {
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, nullptr, lm,
layers);
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID);
ModifyFrameMetrics(
root, [](FrameMetrics& metrics) { metrics.SetIsRootContent(true); });
// away from the scrolling container layer.
EventRegions regions(nsIntRegion(IntRect(0, 0, 100, 100)));
// bottom half is dispatch-to-content
@ -334,53 +331,16 @@ TEST_F(APZEventRegionsTester, HandledByRootApzcFlag) {
MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
UpdateHitTestingTree();
// Tap the top half and check that we report that the event was
// handled by the root APZC.
// Tap the top half and check that we don't report hitting a region
// with APZ-aware listeners.
APZEventResult result =
TouchDown(manager, ScreenIntPoint(50, 25), mcc->Time());
TouchUp(manager, ScreenIntPoint(50, 25), mcc->Time());
EXPECT_EQ(result.mHandledByRootApzc, Some(true));
EXPECT_FALSE(result.mHitRegionWithApzAwareListeners);
// Tap the bottom half and check that we report that we're not
// sure whether the event was handled by the root APZC.
// Tap the bottom half and check we do report hitting a region with
// APZ-aware listeners.
result = TouchDown(manager, ScreenIntPoint(50, 75), mcc->Time());
TouchUp(manager, ScreenIntPoint(50, 75), mcc->Time());
EXPECT_EQ(result.mHandledByRootApzc, Nothing());
// Register an input block callback that will tell us the
// delayed answer.
Maybe<bool> delayedAnswer;
manager->AddInputBlockCallback(result.mInputBlockId,
[&](uint64_t id, bool answer) {
EXPECT_EQ(id, result.mInputBlockId);
delayedAnswer = Some(answer);
});
// Send APZ the relevant notifications to allow it to process the
// input block.
manager->SetAllowedTouchBehavior(result.mInputBlockId,
{AllowedTouchBehavior::VERTICAL_PAN});
manager->SetTargetAPZC(result.mInputBlockId, {result.mTargetGuid});
manager->ContentReceivedInputBlock(result.mInputBlockId,
/*preventDefault=*/false);
// Check that we received the delayed answer and it is what we expect.
EXPECT_EQ(delayedAnswer, Some(true));
// Now repeat the tap on the bottom half, but simulate a prevent-default.
// This time, we expect a delayed answer of false.
result = TouchDown(manager, ScreenIntPoint(50, 75), mcc->Time());
TouchUp(manager, ScreenIntPoint(50, 75), mcc->Time());
EXPECT_EQ(result.mHandledByRootApzc, Nothing());
manager->AddInputBlockCallback(result.mInputBlockId,
[&](uint64_t id, bool answer) {
EXPECT_EQ(id, result.mInputBlockId);
delayedAnswer = Some(answer);
});
manager->SetAllowedTouchBehavior(result.mInputBlockId,
{AllowedTouchBehavior::VERTICAL_PAN});
manager->SetTargetAPZC(result.mInputBlockId, {result.mTargetGuid});
manager->ContentReceivedInputBlock(result.mInputBlockId,
/*preventDefault=*/true);
EXPECT_EQ(delayedAnswer, Some(false));
EXPECT_TRUE(result.mHitRegionWithApzAwareListeners);
}

View File

@ -105,12 +105,6 @@ APZInputBridge* APZCTreeManagerChild::InputBridge() {
return mInputBridge.get();
}
void APZCTreeManagerChild::AddInputBlockCallback(
uint64_t aInputBlockId, InputBlockCallback&& aCallback) {
MOZ_RELEASE_ASSERT(false,
"Remoting of input block callbacks is not implemented");
}
void APZCTreeManagerChild::AddIPDLReference() {
MOZ_ASSERT(mIPCOpen == false);
mIPCOpen = true;

View File

@ -62,9 +62,6 @@ class APZCTreeManagerChild : public IAPZCTreeManager,
APZInputBridge* InputBridge() override;
void AddInputBlockCallback(uint64_t aInputBlockId,
InputBlockCallback&& aCallback) override;
void AddIPDLReference();
void ReleaseIPDLReference();
void ActorDestroy(ActorDestroyReason aWhy) override;

View File

@ -551,7 +551,8 @@ struct ParamTraits<mozilla::layers::APZEventResult> {
WriteParam(aMsg, aParam.mStatus);
WriteParam(aMsg, aParam.mTargetGuid);
WriteParam(aMsg, aParam.mInputBlockId);
WriteParam(aMsg, aParam.mHandledByRootApzc);
WriteParam(aMsg, aParam.mHitRegionWithApzAwareListeners);
WriteParam(aMsg, aParam.mTargetIsRoot);
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
@ -559,7 +560,8 @@ struct ParamTraits<mozilla::layers::APZEventResult> {
return (ReadParam(aMsg, aIter, &aResult->mStatus) &&
ReadParam(aMsg, aIter, &aResult->mTargetGuid) &&
ReadParam(aMsg, aIter, &aResult->mInputBlockId) &&
ReadParam(aMsg, aIter, &aResult->mHandledByRootApzc));
ReadParam(aMsg, aIter, &aResult->mHitRegionWithApzAwareListeners) &&
ReadParam(aMsg, aIter, &aResult->mTargetIsRoot));
}
};

View File

@ -1244,7 +1244,8 @@ package org.mozilla.geckoview {
method public boolean getAutofillEnabled();
method @NonNull public PanZoomController getPanZoomController();
method @AnyThread @Nullable public GeckoSession getSession();
method @NonNull public GeckoResult<Integer> onTouchEventForResult(@NonNull MotionEvent);
method public int onGenericMotionEventForResult(@NonNull MotionEvent);
method public int onTouchEventForResult(@NonNull MotionEvent);
method @UiThread @Nullable public GeckoSession releaseSession();
method public void setAutofillEnabled(boolean);
method public void setDynamicToolbarMaxHeight(int);
@ -1418,10 +1419,9 @@ package org.mozilla.geckoview {
@UiThread public class PanZoomController {
ctor protected PanZoomController(GeckoSession);
method public float getScrollFactor();
method public void onMotionEvent(@NonNull MotionEvent);
method public void onMouseEvent(@NonNull MotionEvent);
method public void onTouchEvent(@NonNull MotionEvent);
method @NonNull public GeckoResult<Integer> onTouchEventForResult(@NonNull MotionEvent);
method public int onMotionEvent(@NonNull MotionEvent);
method public int onMouseEvent(@NonNull MotionEvent);
method public int onTouchEvent(@NonNull MotionEvent);
method @UiThread public void scrollBy(@NonNull ScreenLength, @NonNull ScreenLength);
method @UiThread public void scrollBy(@NonNull ScreenLength, @NonNull ScreenLength, int);
method @UiThread public void scrollTo(@NonNull ScreenLength, @NonNull ScreenLength);

View File

@ -1,45 +0,0 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="height=device-height,width=device-width,initial-scale=1.0">
<style type="text/css">
body {
background-color: white;
margin: 0;
}
#one {
background-color: red;
width: 100%;
height: 33vh;
}
#two {
background-color: green;
width: 100%;
height: 33vh;
}
#three {
background-color: blue;
width: 100%;
height: 33vh;
}
</style>
</head>
<body>
<div id="one"></div>
<div id="two"></div>
<div id="three"></div>
<script>
document.getElementById('two').addEventListener('touchstart', e => {
console.log('preventing default');
e.preventDefault();
});
document.getElementById('three').addEventListener('touchstart', e => {
console.log('not preventing default');
});
</script>
</body>
</html>

View File

@ -74,8 +74,6 @@ open class BaseSessionTest(noErrorCollector: Boolean = false) {
const val IFRAME_UNKNOWN_PROTOCOL = "/assets/www/iframe_unknown_protocol.html"
const val MEDIA_SESSION_DOM1_PATH = "/assets/www/media_session_dom1.html"
const val MEDIA_SESSION_DEFAULT1_PATH = "/assets/www/media_session_default1.html"
const val TOUCH_HTML_PATH = "/assets/www/touch.html"
const val TEST_ENDPOINT = GeckoSessionTestRule.TEST_ENDPOINT
}

View File

@ -1,7 +1,5 @@
package org.mozilla.geckoview.test
import android.os.SystemClock
import android.view.MotionEvent
import org.mozilla.geckoview.ScreenLength
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
@ -10,7 +8,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import org.hamcrest.Matchers.*
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.geckoview.GeckoResult
import org.mozilla.geckoview.PanZoomController
@RunWith(AndroidJUnit4::class)
@ -19,7 +16,7 @@ class PanZoomControllerTest : BaseSessionTest() {
private val errorEpsilon = 3.0
private val scrollWaitTimeout = 10000.0 // 10 seconds
private fun setupScroll() {
private fun setup() {
sessionRule.setPrefsUntilTestEnd(mapOf("dom.visualviewport.enabled" to true))
sessionRule.session.loadTestPath(SCROLL_TEST_PATH)
sessionRule.waitForPageStop()
@ -53,7 +50,7 @@ class PanZoomControllerTest : BaseSessionTest() {
private fun scrollByVertical(mode: Int) {
setupScroll()
setup()
val vh = mainSession.evaluateJS("window.visualViewport.height") as Double
assertThat("Visual viewport height is not zero", vh, greaterThan(0.0))
sessionRule.session.panZoomController.scrollBy(ScreenLength.zero(), ScreenLength.fromVisualViewportHeight(1.0), mode)
@ -64,7 +61,7 @@ class PanZoomControllerTest : BaseSessionTest() {
private fun scrollByHorizontal(mode: Int) {
setupScroll()
setup()
val vw = mainSession.evaluateJS("window.visualViewport.width") as Double
assertThat("Visual viewport width is not zero", vw, greaterThan(0.0))
sessionRule.session.panZoomController.scrollBy(ScreenLength.fromVisualViewportWidth(1.0), ScreenLength.zero(), mode)
@ -98,7 +95,7 @@ class PanZoomControllerTest : BaseSessionTest() {
}
private fun scrollByVerticalTwice(mode: Int) {
setupScroll()
setup()
val vh = mainSession.evaluateJS("window.visualViewport.height") as Double
assertThat("Visual viewport height is not zero", vh, greaterThan(0.0))
sessionRule.session.panZoomController.scrollBy(ScreenLength.zero(), ScreenLength.fromVisualViewportHeight(1.0), mode)
@ -122,7 +119,7 @@ class PanZoomControllerTest : BaseSessionTest() {
}
private fun scrollToVertical(mode: Int) {
setupScroll()
setup()
val vh = mainSession.evaluateJS("window.visualViewport.height") as Double
assertThat("Visual viewport height is not zero", vh, greaterThan(0.0))
sessionRule.session.panZoomController.scrollTo(ScreenLength.zero(), ScreenLength.fromVisualViewportHeight(1.0), mode)
@ -133,7 +130,7 @@ class PanZoomControllerTest : BaseSessionTest() {
private fun scrollToHorizontal(mode: Int) {
setupScroll()
setup()
val vw = mainSession.evaluateJS("window.visualViewport.width") as Double
assertThat("Visual viewport width is not zero", vw, greaterThan(0.0))
sessionRule.session.panZoomController.scrollTo(ScreenLength.fromVisualViewportWidth(1.0), ScreenLength.zero(), mode)
@ -167,7 +164,7 @@ class PanZoomControllerTest : BaseSessionTest() {
}
private fun scrollToVerticalOnZoomedContent(mode: Int) {
setupScroll()
setup()
val originalVH = mainSession.evaluateJS("window.visualViewport.height") as Double
assertThat("Visual viewport height is not zero", originalVH, greaterThan(0.0))
@ -207,7 +204,7 @@ class PanZoomControllerTest : BaseSessionTest() {
}
private fun scrollToVerticalTwice(mode: Int) {
setupScroll()
setup()
val vh = mainSession.evaluateJS("window.visualViewport.height") as Double
assertThat("Visual viewport height is not zero", vh, greaterThan(0.0))
sessionRule.session.panZoomController.scrollTo(ScreenLength.zero(), ScreenLength.fromVisualViewportHeight(1.0), mode)
@ -229,47 +226,4 @@ class PanZoomControllerTest : BaseSessionTest() {
fun scrollToVerticalTwiceAuto() {
scrollToVerticalTwice(PanZoomController.SCROLL_BEHAVIOR_AUTO)
}
private fun setupTouch() {
sessionRule.session.loadTestPath(TOUCH_HTML_PATH)
sessionRule.waitForPageStop()
}
private fun sendDownEvent(x: Float, y: Float): GeckoResult<Int> {
val downTime = SystemClock.uptimeMillis();
val down = MotionEvent.obtain(
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, x, y, 0);
val result = mainSession.panZoomController.onTouchEventForResult(down)
val up = MotionEvent.obtain(
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y, 0);
mainSession.panZoomController.onTouchEvent(up)
return result
}
@WithDisplay(width = 100, height = 100)
@Test
fun touchEventForResult() {
setupTouch()
// No touch handlers, without scrolling
var value = sessionRule.waitForResult(sendDownEvent(50f, 15f))
assertThat("Value should match", value, equalTo(PanZoomController.INPUT_RESULT_UNHANDLED))
// Touch handler with preventDefault
value = sessionRule.waitForResult(sendDownEvent(50f, 45f))
assertThat("Value should match", value, equalTo(PanZoomController.INPUT_RESULT_HANDLED_CONTENT))
// Touch handler without preventDefault
value = sessionRule.waitForResult(sendDownEvent(50f, 75f))
assertThat("Value should match", value, equalTo(PanZoomController.INPUT_RESULT_HANDLED))
// No touch handlers, with scrolling
setupScroll()
value = sessionRule.waitForResult(sendDownEvent(50f, 50f))
assertThat("Value should match", value, equalTo(PanZoomController.INPUT_RESULT_HANDLED))
}
}

View File

@ -739,7 +739,7 @@ public class GeckoView extends FrameLayout {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(final MotionEvent event) {
mSession.getPanZoomController().onTouchEventForResult(event);
onTouchEventForResult(event);
return true;
}
@ -748,43 +748,51 @@ public class GeckoView extends FrameLayout {
* {@link #onTouchEvent(MotionEvent)}, but instead returns a {@link PanZoomController.InputResult}
* indicating how the event was handled.
*
* NOTE: It is highly recommended to only call this with ACTION_DOWN or in otherwise
* limited capacity. Returning a GeckoResult for every touch event will generate
* a lot of allocations and unnecessary GC pressure.
*
* @param event A {@link MotionEvent}
* @return One of the {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) indicating how the event was handled.
*/
public @NonNull GeckoResult<Integer> onTouchEventForResult(final @NonNull MotionEvent event) {
public @PanZoomController.InputResult int onTouchEventForResult(final @NonNull MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
requestFocus();
}
if (mSession == null) {
return GeckoResult.fromValue(PanZoomController.INPUT_RESULT_UNHANDLED);
return PanZoomController.INPUT_RESULT_UNHANDLED;
}
// NOTE: Treat mouse events as "touch" rather than as "mouse", so mouse can be
// used to pan/zoom. Call onMouseEvent() instead for behavior similar to desktop.
return mSession.getPanZoomController().onTouchEventForResult(event);
return mSession.getPanZoomController().onTouchEvent(event);
}
@Override
public boolean onGenericMotionEvent(final MotionEvent event) {
onGenericMotionEventForResult(event);
return true;
}
/**
* Dispatches a {@link MotionEvent} to the {@link PanZoomController}. This is the same as
* {@link #onGenericMotionEvent(MotionEvent)} (MotionEvent)}, but instead returns
* a {@link PanZoomController.InputResult} indicating how the event was handled.
*
* @param event A {@link MotionEvent}
* @return One of the {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) indicating how the event was handled.
*/
public @PanZoomController.InputResult int onGenericMotionEventForResult(final @NonNull MotionEvent event) {
if (AndroidGamepadManager.handleMotionEvent(event)) {
return true;
return PanZoomController.INPUT_RESULT_HANDLED;
}
if (mSession == null) {
return true;
return PanZoomController.INPUT_RESULT_UNHANDLED;
}
if (mSession.getAccessibility().onMotionEvent(event)) {
return true;
return PanZoomController.INPUT_RESULT_HANDLED;
}
mSession.getPanZoomController().onMotionEvent(event);
return true;
return mSession.getPanZoomController().onMotionEvent(event);
}
@Override

View File

@ -98,10 +98,10 @@ public class PanZoomController {
}
@WrapForJNI(calledFrom = "ui")
private native void handleMotionEvent(
private native @InputResult int handleMotionEvent(
int action, int actionIndex, long time, int metaState, float screenX, float screenY,
int pointerId[], float x[], float y[], float orientation[], float pressure[],
float toolMajor[], float toolMinor[], GeckoResult<Integer> result);
float toolMajor[], float toolMinor[]);
@WrapForJNI(calledFrom = "ui")
private native @InputResult int handleScrollEvent(
@ -150,15 +150,10 @@ public class PanZoomController {
/* package */ final NativeProvider mNative = new NativeProvider();
private void handleMotionEvent(final MotionEvent event) {
handleMotionEvent(event, null);
}
private void handleMotionEvent(final MotionEvent event, final GeckoResult<Integer> result) {
private @InputResult int handleMotionEvent(final MotionEvent event) {
if (!mAttached) {
mQueuedEvents.add(new Pair<>(EVENT_SOURCE_MOTION, event));
result.complete(INPUT_RESULT_HANDLED);
return;
return INPUT_RESULT_HANDLED;
}
final int action = event.getActionMasked();
@ -167,8 +162,7 @@ public class PanZoomController {
if (action == MotionEvent.ACTION_DOWN) {
mLastDownTime = event.getDownTime();
} else if (mLastDownTime != event.getDownTime()) {
result.complete(INPUT_RESULT_UNHANDLED);
return;
return INPUT_RESULT_UNHANDLED;
}
final int[] pointerId = new int[count];
@ -206,9 +200,9 @@ public class PanZoomController {
mSession.onScreenOriginChanged((int)screenX, (int)screenY);
}
mNative.handleMotionEvent(action, event.getActionIndex(), event.getEventTime(),
event.getMetaState(), screenX, screenY, pointerId, x, y,
orientation, pressure, toolMajor, toolMinor, result);
return mNative.handleMotionEvent(action, event.getActionIndex(), event.getEventTime(),
event.getMetaState(), screenX, screenY, pointerId, x, y,
orientation, pressure, toolMajor, toolMinor);
}
private @InputResult int handleScrollEvent(final MotionEvent event) {
@ -320,41 +314,15 @@ public class PanZoomController {
* display surface.
*
* @param event MotionEvent to process.
* @return One of the {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) constants indicating how the event was handled.
*/
public void onTouchEvent(final @NonNull MotionEvent event) {
public @InputResult int onTouchEvent(final @NonNull MotionEvent event) {
ThreadUtils.assertOnUiThread();
if (!sTreatMouseAsTouch && event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
return;
return handleMouseEvent(event);
}
handleMotionEvent(event);
}
/**
* Process a touch event through the pan-zoom controller. Treat any mouse events as
* "touch" rather than as "mouse". Pointer coordinates should be relative to the
* display surface.
*
* NOTE: It is highly recommended to only call this with ACTION_DOWN or in otherwise
* limited capacity. Returning a GeckoResult for every touch event will generate
* a lot of allocations and unnecessary GC pressure. Instead, prefer to call
* {@link #onTouchEvent(MotionEvent)}.
*
* @param event MotionEvent to process.
* @return A GeckoResult resolving to one of the
* {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) constants indicating
* how the event was handled.
*/
public @NonNull GeckoResult<Integer> onTouchEventForResult(final @NonNull MotionEvent event) {
ThreadUtils.assertOnUiThread();
if (!sTreatMouseAsTouch && event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
return GeckoResult.fromValue(handleMouseEvent(event));
}
final GeckoResult<Integer> result = new GeckoResult<>();
handleMotionEvent(event, result);
return result;
return handleMotionEvent(event);
}
/**
@ -363,14 +331,15 @@ public class PanZoomController {
* display surface.
*
* @param event MotionEvent to process.
* @return One of the {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) constants indicating how the event was handled.
*/
public void onMouseEvent(final @NonNull MotionEvent event) {
public @InputResult int onMouseEvent(final @NonNull MotionEvent event) {
ThreadUtils.assertOnUiThread();
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
return;
return handleMouseEvent(event);
}
handleMotionEvent(event);
return handleMotionEvent(event);
}
@Override
@ -384,8 +353,9 @@ public class PanZoomController {
* display surface.
*
* @param event MotionEvent to process.
* @return One of the {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) indicating how the event was handled.
*/
public void onMotionEvent(final @NonNull MotionEvent event) {
public @InputResult int onMotionEvent(final @NonNull MotionEvent event) {
ThreadUtils.assertOnUiThread();
final int action = event.getActionMasked();
@ -395,13 +365,15 @@ public class PanZoomController {
} else if ((InputDevice.getDevice(event.getDeviceId()) != null) &&
(InputDevice.getDevice(event.getDeviceId()).getSources() &
InputDevice.SOURCE_TOUCHPAD) == InputDevice.SOURCE_TOUCHPAD) {
return;
return INPUT_RESULT_UNHANDLED;
}
handleScrollEvent(event);
return handleScrollEvent(event);
} else if ((action == MotionEvent.ACTION_HOVER_MOVE) ||
(action == MotionEvent.ACTION_HOVER_ENTER) ||
(action == MotionEvent.ACTION_HOVER_EXIT)) {
handleMouseEvent(event);
return handleMouseEvent(event);
} else {
return INPUT_RESULT_UNHANDLED;
}
}

View File

@ -16,13 +16,9 @@ exclude: true
## v81
- Added `cookiePurging` to [`ContentBlocking.Settings.Builder`][81.1] and `getCookiePurging` and `setCookiePurging`
to [`ContentBlocking.Settings`][81.2].
⚠️ - Changed [`GeckoView.onTouchEventForResult`][81.3] to return a `GeckoResult`, as it now
makes a round-trip to Gecko. The result will be more accurate now, since how content treats
the event is now considered.
[81.1]: {{javadoc_uri}}/ContentBlocking.Settings.Builder.html
[81.2]: {{javadoc_uri}}/ContentBlocking.Settings.html
[81.3]: {{javadoc_uri}}/GeckoView.html#onTouchEventForResult-android.view.MotionEvent-
## v80
- Removed `GeckoSession.hashCode` and `GeckoSession.equals` overrides in favor
@ -765,4 +761,4 @@ to allow adding gecko profiler markers.
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
[65.25]: {{javadoc_uri}}/GeckoResult.html
[api-version]: 9ee462cf1333c166efa9749ee87bbfd7675dfb81
[api-version]: a3245a37268efa5b1bbf787a3aca046670d36cdb

View File

@ -34,17 +34,12 @@
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/layers/RenderTrace.h"
#include <algorithm>
using mozilla::Unused;
using mozilla::dom::ContentChild;
using mozilla::dom::ContentParent;
using mozilla::gfx::DataSourceSurface;
using mozilla::gfx::IntSize;
using mozilla::gfx::Matrix;
using mozilla::gfx::SurfaceFormat;
#include "nsWindow.h"
@ -883,9 +878,10 @@ class nsWindow::NPZCSupport final
WheelDeltaAdjustmentStrategy::eNone);
APZEventResult result = controller->InputBridge()->ReceiveInputEvent(input);
int32_t ret = (result.mHandledByRootApzc == Some(true))
? INPUT_RESULT_HANDLED
: INPUT_RESULT_HANDLED_CONTENT;
int32_t ret =
!result.mTargetIsRoot || result.mHitRegionWithApzAwareListeners
? INPUT_RESULT_HANDLED_CONTENT
: INPUT_RESULT_HANDLED;
if (result.mStatus == nsEventStatus_eConsumeNoDefault) {
return ret;
@ -1006,9 +1002,10 @@ class nsWindow::NPZCSupport final
GetEventTimeStamp(aTime), GetModifiers(aMetaState));
APZEventResult result = controller->InputBridge()->ReceiveInputEvent(input);
int32_t ret = (result.mHandledByRootApzc == Some(true))
? INPUT_RESULT_HANDLED
: INPUT_RESULT_HANDLED_CONTENT;
int32_t ret =
!result.mTargetIsRoot || result.mHitRegionWithApzAwareListeners
? INPUT_RESULT_HANDLED_CONTENT
: INPUT_RESULT_HANDLED;
if (result.mStatus == nsEventStatus_eConsumeNoDefault) {
return ret;
@ -1030,17 +1027,15 @@ class nsWindow::NPZCSupport final
}
}
void HandleMotionEvent(
int32_t HandleMotionEvent(
const java::PanZoomController::NativeProvider::LocalRef& aInstance,
int32_t aAction, int32_t aActionIndex, int64_t aTime, int32_t aMetaState,
float aScreenX, float aScreenY, jni::IntArray::Param aPointerId,
jni::FloatArray::Param aX, jni::FloatArray::Param aY,
jni::FloatArray::Param aOrientation, jni::FloatArray::Param aPressure,
jni::FloatArray::Param aToolMajor, jni::FloatArray::Param aToolMinor,
jni::Object::Param aResult) {
jni::FloatArray::Param aToolMajor, jni::FloatArray::Param aToolMinor) {
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
auto returnResult = java::GeckoResult::Ref::From(aResult);
RefPtr<IAPZCTreeManager> controller;
if (LockedWindowPtr window{mWindow}) {
@ -1048,11 +1043,7 @@ class nsWindow::NPZCSupport final
}
if (!controller) {
if (returnResult) {
returnResult->Complete(
java::sdk::Integer::ValueOf(INPUT_RESULT_UNHANDLED));
}
return;
return INPUT_RESULT_UNHANDLED;
}
nsTArray<int32_t> pointerId(aPointerId->GetElements());
@ -1081,11 +1072,7 @@ class nsWindow::NPZCSupport final
type = MultiTouchInput::MULTITOUCH_CANCEL;
break;
default:
if (returnResult) {
returnResult->Complete(
java::sdk::Integer::ValueOf(INPUT_RESULT_UNHANDLED));
}
return;
return INPUT_RESULT_UNHANDLED;
}
MultiTouchInput input(type, aTime, GetEventTimeStamp(aTime), 0);
@ -1142,15 +1129,13 @@ class nsWindow::NPZCSupport final
}
APZEventResult result = controller->InputBridge()->ReceiveInputEvent(input);
int32_t handled = (result.mHandledByRootApzc == Some(true))
? INPUT_RESULT_HANDLED
: INPUT_RESULT_HANDLED_CONTENT;
int32_t ret =
!result.mTargetIsRoot || result.mHitRegionWithApzAwareListeners
? INPUT_RESULT_HANDLED_CONTENT
: INPUT_RESULT_HANDLED;
if (result.mStatus == nsEventStatus_eConsumeNoDefault) {
if (returnResult) {
returnResult->Complete(java::sdk::Integer::ValueOf(handled));
}
return;
return ret;
}
// Dispatch APZ input event on Gecko thread.
@ -1160,40 +1145,15 @@ class nsWindow::NPZCSupport final
window->DispatchHitTest(touchEvent);
});
if (!returnResult) {
// We don't care how APZ handled the event so we're done here.
return;
switch (result.mStatus) {
case nsEventStatus_eIgnore:
return INPUT_RESULT_UNHANDLED;
case nsEventStatus_eConsumeDoDefault:
return ret;
default:
MOZ_ASSERT_UNREACHABLE("Unexpected nsEventStatus");
return INPUT_RESULT_UNHANDLED;
}
if (result.mHandledByRootApzc != Nothing()) {
// We know conclusively that the root APZ handled this or not and
// don't need to do any more work.
switch (result.mStatus) {
case nsEventStatus_eIgnore:
returnResult->Complete(
java::sdk::Integer::ValueOf(INPUT_RESULT_UNHANDLED));
break;
case nsEventStatus_eConsumeDoDefault:
returnResult->Complete(java::sdk::Integer::ValueOf(handled));
break;
default:
MOZ_ASSERT_UNREACHABLE("Unexpected nsEventStatus");
returnResult->Complete(
java::sdk::Integer::ValueOf(INPUT_RESULT_UNHANDLED));
break;
}
return;
}
// Wait to see if APZ handled the event or not...
controller->AddInputBlockCallback(
result.mInputBlockId,
[returnResult = java::GeckoResult::GlobalRef(returnResult)](
uint64_t aInputBlockId, bool aHandledByRootApzc) {
returnResult->Complete(java::sdk::Integer::ValueOf(
aHandledByRootApzc ? INPUT_RESULT_HANDLED
: INPUT_RESULT_HANDLED_CONTENT));
});
}
};