mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1120683 - Properly handle unapplying 3D projective transforms throughout APZ code. r=botond
Whenever the inverse of a 3D projective transform is applied to a point, only use the result if it has a positive w-coordinate. When transforming by a matrix that we know should be 2D, assert to that effect. Transformations of rectangles (as opposed to points) remain to be audited.
This commit is contained in:
parent
db609af9f5
commit
b4ac13dd45
@ -605,6 +605,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
||||
// gecko space should only consist of overscroll-cancelling transforms.
|
||||
Matrix4x4 transformToGecko = GetScreenToApzcTransform(apzc)
|
||||
* GetApzcToGeckoTransform(apzc);
|
||||
MOZ_ASSERT(transformToGecko.Is2D());
|
||||
ScreenPoint untransformedOrigin = TransformTo<ScreenPixel>(
|
||||
transformToGecko, wheelInput.mOrigin);
|
||||
|
||||
@ -634,6 +635,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
||||
apzc->GetGuid(aOutTargetGuid);
|
||||
Matrix4x4 transformToGecko = GetScreenToApzcTransform(apzc)
|
||||
* GetApzcToGeckoTransform(apzc);
|
||||
MOZ_ASSERT(transformToGecko.Is2D());
|
||||
panInput.mPanStartPoint = TransformTo<ScreenPixel>(
|
||||
transformToGecko, panInput.mPanStartPoint);
|
||||
panInput.mPanDisplacement = TransformVector<ScreenPixel>(
|
||||
@ -656,6 +658,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
||||
apzc->GetGuid(aOutTargetGuid);
|
||||
Matrix4x4 outTransform = GetScreenToApzcTransform(apzc)
|
||||
* GetApzcToGeckoTransform(apzc);
|
||||
MOZ_ASSERT(outTransform.Is2D());
|
||||
pinchInput.mFocusPoint = TransformTo<ScreenPixel>(
|
||||
outTransform, pinchInput.mFocusPoint);
|
||||
}
|
||||
@ -676,6 +679,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
||||
apzc->GetGuid(aOutTargetGuid);
|
||||
Matrix4x4 outTransform = GetScreenToApzcTransform(apzc)
|
||||
* GetApzcToGeckoTransform(apzc);
|
||||
MOZ_ASSERT(outTransform.Is2D());
|
||||
tapInput.mPoint = TransformTo<ScreenPixel>(outTransform, tapInput.mPoint);
|
||||
}
|
||||
break;
|
||||
@ -785,6 +789,8 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
|
||||
Matrix4x4 transformToApzc = GetScreenToApzcTransform(mApzcForInputBlock);
|
||||
Matrix4x4 transformToGecko = GetApzcToGeckoTransform(mApzcForInputBlock);
|
||||
Matrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
MOZ_ASSERT(outTransform.Is2D());
|
||||
|
||||
for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
|
||||
SingleTouchData& touchData = aInput.mTouches[i];
|
||||
touchData.mScreenPoint = TransformTo<ScreenPixel>(
|
||||
@ -825,6 +831,7 @@ APZCTreeManager::TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
|
||||
Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
|
||||
Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
|
||||
Matrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
MOZ_ASSERT(outTransform.Is2D());
|
||||
*aOutTransformedPoint = TransformTo<LayoutDevicePixel>(outTransform, aPoint);
|
||||
}
|
||||
}
|
||||
@ -892,6 +899,7 @@ APZCTreeManager::ProcessEvent(WidgetInputEvent& aEvent,
|
||||
Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
|
||||
Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
|
||||
Matrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
MOZ_ASSERT(outTransform.Is2D());
|
||||
aEvent.refPoint = TransformTo<LayoutDevicePixel>(outTransform, aEvent.refPoint);
|
||||
}
|
||||
return result;
|
||||
@ -1188,8 +1196,9 @@ APZCTreeManager::GetRootNode() const
|
||||
* @param aTarget the target APZC
|
||||
* @param aStartPoint the start point of the displacement
|
||||
* @param aEndPoint the end point of the displacement
|
||||
* @return true on success, false if aStartPoint or aEndPoint cannot be transformed into target's coordinate space
|
||||
*/
|
||||
static void
|
||||
static bool
|
||||
TransformDisplacement(APZCTreeManager* aTreeManager,
|
||||
AsyncPanZoomController* aSource,
|
||||
AsyncPanZoomController* aTarget,
|
||||
@ -1200,10 +1209,18 @@ TransformDisplacement(APZCTreeManager* aTreeManager,
|
||||
ScreenPoint screenStart = TransformTo<ScreenPixel>(untransformToApzc, aStartPoint);
|
||||
ScreenPoint screenEnd = TransformTo<ScreenPixel>(untransformToApzc, aEndPoint);
|
||||
|
||||
|
||||
// Convert start and end points to aTarget's ParentLayer coordinates.
|
||||
Matrix4x4 transformToApzc = aTreeManager->GetScreenToApzcTransform(aTarget);
|
||||
aStartPoint = TransformTo<ParentLayerPixel>(transformToApzc, screenStart);
|
||||
aEndPoint = TransformTo<ParentLayerPixel>(transformToApzc, screenEnd);
|
||||
Maybe<ParentLayerPoint> startPoint = UntransformTo<ParentLayerPixel>(transformToApzc, screenStart);
|
||||
Maybe<ParentLayerPoint> endPoint = UntransformTo<ParentLayerPixel>(transformToApzc, screenEnd);
|
||||
if (!startPoint || !endPoint) {
|
||||
return false;
|
||||
}
|
||||
aEndPoint = *endPoint;
|
||||
aStartPoint = *startPoint;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1234,7 +1251,9 @@ APZCTreeManager::DispatchScroll(AsyncPanZoomController* aPrev,
|
||||
// scroll grabbing to grab the scroll from it), don't bother doing the
|
||||
// transformations in that case.
|
||||
if (next != aPrev) {
|
||||
TransformDisplacement(this, aPrev, next, aStartPoint, aEndPoint);
|
||||
if (!TransformDisplacement(this, aPrev, next, aStartPoint, aEndPoint)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll |next|. If this causes overscroll, it will call DispatchScroll()
|
||||
@ -1287,11 +1306,13 @@ APZCTreeManager::DispatchFling(AsyncPanZoomController* aPrev,
|
||||
|
||||
// Only transform when current apcz can be transformed with previous
|
||||
if (startIndex > 0) {
|
||||
TransformDisplacement(this,
|
||||
if (!TransformDisplacement(this,
|
||||
aOverscrollHandoffChain->GetApzcAtIndex(startIndex - 1),
|
||||
current,
|
||||
startPoint,
|
||||
endPoint);
|
||||
endPoint)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
transformedVelocity = endPoint - startPoint;
|
||||
|
@ -951,7 +951,9 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent,
|
||||
switch (aEvent.mInputType) {
|
||||
case MULTITOUCH_INPUT: {
|
||||
MultiTouchInput multiTouchInput = aEvent.AsMultiTouchInput();
|
||||
multiTouchInput.TransformToLocal(aTransformToApzc);
|
||||
if (!multiTouchInput.TransformToLocal(aTransformToApzc)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsRefPtr<GestureEventListener> listener = GetGestureEventListener();
|
||||
if (listener) {
|
||||
@ -972,7 +974,9 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent,
|
||||
}
|
||||
case PANGESTURE_INPUT: {
|
||||
PanGestureInput panGestureInput = aEvent.AsPanGestureInput();
|
||||
panGestureInput.TransformToLocal(aTransformToApzc);
|
||||
if (!panGestureInput.TransformToLocal(aTransformToApzc)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
switch (panGestureInput.mType) {
|
||||
case PanGestureInput::PANGESTURE_MAYSTART: rv = OnPanMayBegin(panGestureInput); break;
|
||||
@ -989,21 +993,27 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent,
|
||||
}
|
||||
case SCROLLWHEEL_INPUT: {
|
||||
ScrollWheelInput scrollInput = aEvent.AsScrollWheelInput();
|
||||
scrollInput.TransformToLocal(aTransformToApzc);
|
||||
if (!scrollInput.TransformToLocal(aTransformToApzc)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = OnScrollWheel(scrollInput);
|
||||
break;
|
||||
}
|
||||
case PINCHGESTURE_INPUT: {
|
||||
PinchGestureInput pinchInput = aEvent.AsPinchGestureInput();
|
||||
pinchInput.TransformToLocal(aTransformToApzc);
|
||||
if (!pinchInput.TransformToLocal(aTransformToApzc)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = HandleGestureEvent(pinchInput);
|
||||
break;
|
||||
}
|
||||
case TAPGESTURE_INPUT: {
|
||||
TapGestureInput tapInput = aEvent.AsTapGestureInput();
|
||||
tapInput.TransformToLocal(aTransformToApzc);
|
||||
if (!tapInput.TransformToLocal(aTransformToApzc)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = HandleGestureEvent(tapInput);
|
||||
break;
|
||||
@ -1396,12 +1406,14 @@ bool
|
||||
AsyncPanZoomController::ConvertToGecko(const ScreenIntPoint& aPoint, CSSPoint* aOut)
|
||||
{
|
||||
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
|
||||
Matrix4x4 transformToApzc = treeManagerLocal->GetScreenToApzcTransform(this);
|
||||
Matrix4x4 transformToGecko = treeManagerLocal->GetApzcToGeckoTransform(this);
|
||||
Matrix4x4 transformScreenToGecko = treeManagerLocal->GetScreenToApzcTransform(this)
|
||||
* treeManagerLocal->GetApzcToGeckoTransform(this);
|
||||
|
||||
// NOTE: This isn't *quite* LayoutDevicePoint, we just don't have a name
|
||||
// for this coordinate space and it maps the closest to LayoutDevicePoint.
|
||||
MOZ_ASSERT(transformScreenToGecko.Is2D());
|
||||
LayoutDevicePoint layoutPoint = TransformTo<LayoutDevicePixel>(
|
||||
transformToApzc * transformToGecko, aPoint);
|
||||
transformScreenToGecko, aPoint);
|
||||
|
||||
{ // scoped lock to access mFrameMetrics
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
@ -1837,6 +1849,7 @@ ScreenPoint AsyncPanZoomController::ToScreenCoordinates(const ParentLayerPoint&
|
||||
return TransformVector<ScreenPixel>(GetTransformToThis().Inverse(), aVector, aAnchor);
|
||||
}
|
||||
|
||||
// TODO: figure out a good way to check the w-coordinate is positive and return the result
|
||||
ParentLayerPoint AsyncPanZoomController::ToParentLayerCoordinates(const ScreenPoint& aVector,
|
||||
const ScreenPoint& aAnchor) const {
|
||||
return TransformVector<ParentLayerPixel>(GetTransformToThis(), aVector, aAnchor);
|
||||
@ -1845,14 +1858,17 @@ ParentLayerPoint AsyncPanZoomController::ToParentLayerCoordinates(const ScreenPo
|
||||
bool AsyncPanZoomController::Contains(const ScreenIntPoint& aPoint) const
|
||||
{
|
||||
Matrix4x4 transformToThis = GetTransformToThis();
|
||||
ParentLayerIntPoint point = TransformTo<ParentLayerPixel>(transformToThis, aPoint);
|
||||
Maybe<ParentLayerIntPoint> point = UntransformTo<ParentLayerPixel>(transformToThis, aPoint);
|
||||
if (!point) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ParentLayerIntRect cb;
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
GetFrameMetrics().GetCompositionBounds().ToIntRect(&cb);
|
||||
}
|
||||
return cb.Contains(point);
|
||||
return cb.Contains(*point);
|
||||
}
|
||||
|
||||
ScreenCoord AsyncPanZoomController::PanDistance() const {
|
||||
|
@ -207,10 +207,7 @@ HitTestingTreeNode::Untransform(const ParentLayerPoint& aPoint) const
|
||||
if (mApzc) {
|
||||
localTransform = localTransform * mApzc->GetCurrentAsyncTransformWithOverscroll();
|
||||
}
|
||||
gfx::Point4D point = localTransform.Inverse().ProjectPoint(aPoint.ToUnknownPoint());
|
||||
return point.HasPositiveWCoord()
|
||||
? Some(ViewAs<LayerPixel>(point.As2DPoint()))
|
||||
: Nothing();
|
||||
return UntransformTo<LayerPixel>(localTransform.Inverse(), aPoint);
|
||||
}
|
||||
|
||||
HitTestResult
|
||||
|
@ -145,6 +145,45 @@ static gfx::PointTyped<TargetUnits> TransformVector(const gfx::Matrix4x4& aTrans
|
||||
return transformedEnd - transformedStart;
|
||||
}
|
||||
|
||||
// UntransformTo() and UntransformVector() are like TransformTo() and
|
||||
// TransformVector(), respectively, but are intended for cases where
|
||||
// the transformation matrix is the inverse of a 3D projection. When
|
||||
// using such transforms, the resulting Point4D is only meaningful
|
||||
// if it has a positive w-coordinate. To handle this, these functions
|
||||
// return a Maybe object which contains a value if and only if the
|
||||
// result is meaningful
|
||||
template <typename TargetUnits, typename SourceUnits>
|
||||
static Maybe<gfx::PointTyped<TargetUnits>> UntransformTo(const gfx::Matrix4x4& aTransform,
|
||||
const gfx::PointTyped<SourceUnits>& aPoint)
|
||||
{
|
||||
gfx::Point4D point = aTransform.ProjectPoint(aPoint.ToUnknownPoint());
|
||||
if (!point.HasPositiveWCoord()) {
|
||||
return Nothing();
|
||||
}
|
||||
return Some(ViewAs<TargetUnits>(point.As2DPoint()));
|
||||
}
|
||||
template <typename TargetUnits, typename SourceUnits>
|
||||
static Maybe<gfx::IntPointTyped<TargetUnits>> UntransformTo(const gfx::Matrix4x4& aTransform,
|
||||
const gfx::IntPointTyped<SourceUnits>& aPoint)
|
||||
{
|
||||
gfx::Point4D point = aTransform.ProjectPoint(aPoint.ToUnknownPoint());
|
||||
if (!point.HasPositiveWCoord()) {
|
||||
return Nothing();
|
||||
}
|
||||
return Some(RoundedToInt(ViewAs<TargetUnits>(point.As2DPoint())));
|
||||
}
|
||||
template <typename TargetUnits, typename SourceUnits>
|
||||
static Maybe<gfx::PointTyped<TargetUnits>> UntransformVector(const gfx::Matrix4x4& aTransform,
|
||||
const gfx::PointTyped<SourceUnits>& aVector,
|
||||
const gfx::PointTyped<SourceUnits>& aAnchor) {
|
||||
gfx::Point4D point = aTransform.ProjectPoint(aAnchor.ToUnknownPoint() + aVector.ToUnknownPoint())
|
||||
- aTransform.ProjectPoint(aAnchor.ToUnknownPoint());
|
||||
if (!point.HasPositiveWCoord()){
|
||||
return Nothing();
|
||||
}
|
||||
return Some(ViewAs<TargetUnits>(point.As2DPoint()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -212,37 +212,67 @@ MultiTouchInput::MultiTouchInput(const WidgetMouseEvent& aMouseEvent)
|
||||
1.0f));
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
MultiTouchInput::TransformToLocal(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
for (size_t i = 0; i < mTouches.Length(); i++) {
|
||||
mTouches[i].mLocalScreenPoint = TransformTo<ParentLayerPixel>(aTransform, ScreenPoint(mTouches[i].mScreenPoint));
|
||||
Maybe<ParentLayerIntPoint> point = UntransformTo<ParentLayerPixel>(aTransform, mTouches[i].mScreenPoint);
|
||||
if (!point) {
|
||||
return false;
|
||||
}
|
||||
mTouches[i].mLocalScreenPoint = *point;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
PanGestureInput::TransformToLocal(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
mLocalPanStartPoint = TransformTo<ParentLayerPixel>(aTransform, mPanStartPoint);
|
||||
mLocalPanDisplacement = TransformVector<ParentLayerPixel>(aTransform, mPanDisplacement, mPanStartPoint);
|
||||
{
|
||||
Maybe<ParentLayerPoint> panStartPoint = UntransformTo<ParentLayerPixel>(aTransform, mPanStartPoint);
|
||||
if (!panStartPoint) {
|
||||
return false;
|
||||
}
|
||||
mLocalPanStartPoint = *panStartPoint;
|
||||
|
||||
Maybe<ParentLayerPoint> panDisplacement = UntransformVector<ParentLayerPixel>(aTransform, mPanDisplacement, mPanStartPoint);
|
||||
if (!panDisplacement) {
|
||||
return false;
|
||||
}
|
||||
mLocalPanDisplacement = *panDisplacement;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
PinchGestureInput::TransformToLocal(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
mLocalFocusPoint = TransformTo<ParentLayerPixel>(aTransform, mFocusPoint);
|
||||
{
|
||||
Maybe<ParentLayerPoint> point = UntransformTo<ParentLayerPixel>(aTransform, mFocusPoint);
|
||||
if (!point) {
|
||||
return false;
|
||||
}
|
||||
mLocalFocusPoint = *point;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
TapGestureInput::TransformToLocal(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
mLocalPoint = TransformTo<ParentLayerPixel>(aTransform, mPoint);
|
||||
Maybe<ParentLayerIntPoint> point = UntransformTo<ParentLayerPixel>(aTransform, mPoint);
|
||||
if (!point) {
|
||||
return false;
|
||||
}
|
||||
mLocalPoint = *point;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
ScrollWheelInput::TransformToLocal(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
mLocalOrigin = TransformTo<ParentLayerPixel>(aTransform, mOrigin);
|
||||
Maybe<ParentLayerPoint> point = UntransformTo<ParentLayerPixel>(aTransform, mOrigin);
|
||||
if (!point) {
|
||||
return false;
|
||||
}
|
||||
mLocalOrigin = *point;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -239,7 +239,7 @@ public:
|
||||
// and rotation angle.
|
||||
explicit MultiTouchInput(const WidgetMouseEvent& aMouseEvent);
|
||||
|
||||
void TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
bool TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
|
||||
MultiTouchType mType;
|
||||
nsTArray<SingleTouchData> mTouches;
|
||||
@ -311,7 +311,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
bool TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
|
||||
PanGestureType mType;
|
||||
ScreenPoint mPanStartPoint;
|
||||
@ -374,7 +374,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
bool TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
|
||||
PinchGestureType mType;
|
||||
|
||||
@ -444,7 +444,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
bool TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
|
||||
TapGestureType mType;
|
||||
|
||||
@ -506,7 +506,7 @@ public:
|
||||
mDeltaY(aDeltaY)
|
||||
{}
|
||||
|
||||
void TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
bool TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
|
||||
ScrollDeltaType mDeltaType;
|
||||
ScrollMode mScrollMode;
|
||||
|
Loading…
Reference in New Issue
Block a user