mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-18 06:45:33 +00:00
Bug 952977: More gfx::Matrix cleanup in APZC r=nical
This commit is contained in:
parent
fdea561425
commit
30b97efa59
@ -8,7 +8,6 @@
|
||||
#include "CompositorParent.h" // for CompositorParent, etc
|
||||
#include "InputData.h" // for InputData, etc
|
||||
#include "Layers.h" // for ContainerLayer, Layer, etc
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "mozilla/dom/Touch.h" // for Touch
|
||||
#include "mozilla/gfx/Point.h" // for Point
|
||||
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
|
||||
@ -32,6 +31,9 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
typedef mozilla::gfx::Point Point;
|
||||
typedef mozilla::gfx::Matrix4x4 Matrix4x4;
|
||||
|
||||
float APZCTreeManager::sDPI = 160.0;
|
||||
|
||||
APZCTreeManager::APZCTreeManager()
|
||||
@ -139,7 +141,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
aRoot,
|
||||
// aCompositor is null in gtest scenarios
|
||||
aCompositor ? aCompositor->RootLayerTreeId() : 0,
|
||||
gfx3DMatrix(), nullptr, nullptr,
|
||||
Matrix4x4(), nullptr, nullptr,
|
||||
aIsFirstPaint, aOriginatingLayersId,
|
||||
paintLogger, &apzcsToDestroy, nsIntRegion());
|
||||
mApzcTreeLog << "[end]\n";
|
||||
@ -154,7 +156,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
AsyncPanZoomController*
|
||||
APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
Layer* aLayer, uint64_t aLayersId,
|
||||
gfx3DMatrix aTransform,
|
||||
Matrix4x4 aTransform,
|
||||
AsyncPanZoomController* aParent,
|
||||
AsyncPanZoomController* aNextSibling,
|
||||
bool aIsFirstPaint,
|
||||
@ -165,7 +167,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
{
|
||||
mTreeLock.AssertCurrentThreadOwns();
|
||||
|
||||
gfx3DMatrix transform = gfx::To3DMatrix(aLayer->GetTransform());
|
||||
Matrix4x4 transform = aLayer->GetTransform();
|
||||
|
||||
ContainerLayer* container = aLayer->AsContainerLayer();
|
||||
AsyncPanZoomController* apzc = nullptr;
|
||||
@ -319,7 +321,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
// Accumulate the CSS transform between layers that have an APZC, but exclude any
|
||||
// any layers that do have an APZC, and reset the accumulation at those layers.
|
||||
if (apzc) {
|
||||
aTransform = gfx3DMatrix();
|
||||
aTransform = Matrix4x4();
|
||||
} else {
|
||||
// Multiply child layer transforms on the left so they get applied first
|
||||
aTransform = transform * aTransform;
|
||||
@ -341,7 +343,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
// have to check for mask layers and so on in order to properly handle
|
||||
// that case.
|
||||
obscured = aObscured;
|
||||
obscured.Transform(transform.Inverse());
|
||||
obscured.Transform(To3DMatrix(transform).Inverse());
|
||||
}
|
||||
|
||||
// If there's no APZC at this level, any APZCs for our child layers will
|
||||
@ -378,25 +380,25 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
}
|
||||
|
||||
/*static*/ template<class T> void
|
||||
ApplyTransform(gfx::PointTyped<T>* aPoint, const gfx3DMatrix& aMatrix)
|
||||
ApplyTransform(gfx::PointTyped<T>* aPoint, const Matrix4x4& aMatrix)
|
||||
{
|
||||
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
|
||||
Point result = aMatrix * aPoint->ToUnknownPoint();
|
||||
aPoint->x = result.x;
|
||||
aPoint->y = result.y;
|
||||
}
|
||||
|
||||
/*static*/ template<class T> void
|
||||
ApplyTransform(gfx::IntPointTyped<T>* aPoint, const gfx3DMatrix& aMatrix)
|
||||
ApplyTransform(gfx::IntPointTyped<T>* aPoint, const Matrix4x4& aMatrix)
|
||||
{
|
||||
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
|
||||
aPoint->x = NS_lround(result.x);
|
||||
aPoint->y = NS_lround(result.y);
|
||||
Point result = aMatrix * aPoint->ToUnknownPoint();
|
||||
aPoint->x = result.x;
|
||||
aPoint->y = result.y;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
ApplyTransform(nsIntPoint* aPoint, const gfx3DMatrix& aMatrix)
|
||||
ApplyTransform(nsIntPoint* aPoint, const Matrix4x4& aMatrix)
|
||||
{
|
||||
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
|
||||
Point result = aMatrix * Point(aPoint->x, aPoint->y);
|
||||
aPoint->x = NS_lround(result.x);
|
||||
aPoint->y = NS_lround(result.y);
|
||||
}
|
||||
@ -404,7 +406,7 @@ ApplyTransform(nsIntPoint* aPoint, const gfx3DMatrix& aMatrix)
|
||||
/*static*/ template<class T> void
|
||||
TransformScreenToGecko(T* aPoint, AsyncPanZoomController* aApzc, APZCTreeManager* aApzcTm)
|
||||
{
|
||||
gfx3DMatrix transformToApzc, transformToGecko;
|
||||
Matrix4x4 transformToApzc, transformToGecko;
|
||||
aApzcTm->GetInputTransforms(aApzc, transformToApzc, transformToGecko);
|
||||
ApplyTransform(aPoint, transformToApzc * transformToGecko);
|
||||
}
|
||||
@ -414,8 +416,8 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
||||
ScrollableLayerGuid* aOutTargetGuid)
|
||||
{
|
||||
nsEventStatus result = nsEventStatus_eIgnore;
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToGecko;
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko;
|
||||
switch (aEvent.mInputType) {
|
||||
case MULTITOUCH_INPUT: {
|
||||
MultiTouchInput& touchInput = aEvent.AsMultiTouchInput();
|
||||
@ -559,11 +561,11 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
|
||||
|
||||
if (mApzcForInputBlock) {
|
||||
// Cache apz transform so it can be used for future events in this block.
|
||||
gfx3DMatrix transformToGecko;
|
||||
Matrix4x4 transformToGecko;
|
||||
GetInputTransforms(mApzcForInputBlock, mCachedTransformToApzcForInputBlock, transformToGecko);
|
||||
} else {
|
||||
// Reset the cached apz transform
|
||||
mCachedTransformToApzcForInputBlock = gfx3DMatrix();
|
||||
mCachedTransformToApzcForInputBlock = Matrix4x4();
|
||||
}
|
||||
} else if (mApzcForInputBlock) {
|
||||
APZCTM_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get());
|
||||
@ -596,7 +598,7 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
|
||||
// For computing the input for the APZC, used the cached transform.
|
||||
// This ensures that the sequence of touch points an APZC sees in an
|
||||
// input block are all in the same coordinate space.
|
||||
gfx3DMatrix transformToApzc = mCachedTransformToApzcForInputBlock;
|
||||
Matrix4x4 transformToApzc = mCachedTransformToApzcForInputBlock;
|
||||
MultiTouchInput inputForApzc(aInput);
|
||||
for (size_t i = 0; i < inputForApzc.mTouches.Length(); i++) {
|
||||
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
|
||||
@ -606,9 +608,9 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
|
||||
// For computing the event to pass back to Gecko, use the up-to-date transforms.
|
||||
// This ensures that transformToApzc and transformToGecko are in sync
|
||||
// (note that transformToGecko isn't cached).
|
||||
gfx3DMatrix transformToGecko;
|
||||
Matrix4x4 transformToGecko;
|
||||
GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToGecko);
|
||||
gfx3DMatrix outTransform = transformToApzc * transformToGecko;
|
||||
Matrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
|
||||
ApplyTransform(&(aInput.mTouches[i].mScreenPoint), outTransform);
|
||||
}
|
||||
@ -649,10 +651,10 @@ APZCTreeManager::TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
|
||||
MOZ_ASSERT(aOutTransformedPoint);
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aPoint, nullptr);
|
||||
if (apzc && aOutTransformedPoint) {
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToGecko;
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko;
|
||||
GetInputTransforms(apzc, transformToApzc, transformToGecko);
|
||||
gfx3DMatrix outTransform = transformToApzc * transformToGecko;
|
||||
Matrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
aOutTransformedPoint->x = aPoint.x;
|
||||
aOutTransformedPoint->y = aPoint.y;
|
||||
ApplyTransform(aOutTransformedPoint, outTransform);
|
||||
@ -672,10 +674,10 @@ APZCTreeManager::ProcessEvent(WidgetInputEvent& aEvent,
|
||||
&inOverscrolledApzc);
|
||||
if (apzc) {
|
||||
apzc->GetGuid(aOutTargetGuid);
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToGecko;
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko;
|
||||
GetInputTransforms(apzc, transformToApzc, transformToGecko);
|
||||
gfx3DMatrix outTransform = transformToApzc * transformToGecko;
|
||||
Matrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
ApplyTransform(&(aEvent.refPoint), outTransform);
|
||||
}
|
||||
return inOverscrolledApzc ? nsEventStatus_eConsumeNoDefault
|
||||
@ -804,13 +806,15 @@ TransformDisplacement(APZCTreeManager* aTreeManager,
|
||||
AsyncPanZoomController* aTarget,
|
||||
ScreenPoint& aStartPoint,
|
||||
ScreenPoint& aEndPoint) {
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToGecko; // ignored
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko; // ignored
|
||||
|
||||
// Convert start and end points to untransformed screen coordinates.
|
||||
aTreeManager->GetInputTransforms(aSource, transformToApzc, transformToGecko);
|
||||
ApplyTransform(&aStartPoint, transformToApzc.Inverse());
|
||||
ApplyTransform(&aEndPoint, transformToApzc.Inverse());
|
||||
Matrix4x4 untransformToApzc = transformToApzc;
|
||||
untransformToApzc.Invert();
|
||||
ApplyTransform(&aStartPoint, untransformToApzc);
|
||||
ApplyTransform(&aEndPoint, untransformToApzc);
|
||||
|
||||
// Convert start and end points to aTarget's transformed screen coordinates.
|
||||
aTreeManager->GetInputTransforms(aTarget, transformToApzc, transformToGecko);
|
||||
@ -1180,12 +1184,13 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
|
||||
// to aApzc's parent layer's layer coordinates.
|
||||
// It is OC.Inverse() * NC.Inverse() * MC.Inverse() at recursion level for L,
|
||||
// and RC.Inverse() * QC.Inverse() at recursion level for P.
|
||||
gfx3DMatrix ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
|
||||
Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform();
|
||||
ancestorUntransform.Invert();
|
||||
|
||||
// Hit testing for this layer takes place in our parent layer coordinates,
|
||||
// since the composition bounds (used to initialize the visible rect against
|
||||
// which we hit test are in those coordinates).
|
||||
gfxPointH3D hitTestPointForThisLayer = ancestorUntransform.ProjectPoint(aHitTestPoint);
|
||||
gfxPointH3D hitTestPointForThisLayer = To3DMatrix(ancestorUntransform).ProjectPoint(aHitTestPoint);
|
||||
APZCTM_LOG("Untransformed %f %f to transient coordinates %f %f for hit-testing APZC %p\n",
|
||||
aHitTestPoint.x, aHitTestPoint.y,
|
||||
hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc);
|
||||
@ -1194,10 +1199,12 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
|
||||
// to aApzc's layer coordinates (which are aApzc's children's ParentLayer coordinates).
|
||||
// It is OC.Inverse() * NC.Inverse() * MC.Inverse() * LC.Inverse() * LA.Inverse() at L
|
||||
// and RC.Inverse() * QC.Inverse() * PC.Inverse() * PA.Inverse() at P.
|
||||
gfx3DMatrix childUntransform = ancestorUntransform
|
||||
* aApzc->GetCSSTransform().Inverse()
|
||||
* gfx::To3DMatrix(aApzc->GetCurrentAsyncTransform()).Inverse();
|
||||
gfxPointH3D hitTestPointForChildLayers = childUntransform.ProjectPoint(aHitTestPoint);
|
||||
Matrix4x4 cssUntransform = aApzc->GetCSSTransform();
|
||||
cssUntransform.Invert();
|
||||
Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransform();
|
||||
asyncUntransform.Invert();
|
||||
Matrix4x4 childUntransform = ancestorUntransform * cssUntransform * asyncUntransform;
|
||||
gfxPointH3D hitTestPointForChildLayers = To3DMatrix(childUntransform).ProjectPoint(aHitTestPoint);
|
||||
APZCTM_LOG("Untransformed %f %f to layer coordinates %f %f for APZC %p\n",
|
||||
aHitTestPoint.x, aHitTestPoint.y,
|
||||
hitTestPointForChildLayers.x, hitTestPointForChildLayers.y, aApzc);
|
||||
@ -1330,8 +1337,8 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
|
||||
required can be generated.
|
||||
*/
|
||||
void
|
||||
APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
|
||||
gfx3DMatrix& aTransformToGeckoOut)
|
||||
APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, Matrix4x4& aTransformToApzcOut,
|
||||
Matrix4x4& aTransformToGeckoOut)
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
|
||||
@ -1342,26 +1349,36 @@ APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix&
|
||||
// leftmost matrix in a multiplication is applied first.
|
||||
|
||||
// ancestorUntransform is OC.Inverse() * NC.Inverse() * MC.Inverse()
|
||||
gfx3DMatrix ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
|
||||
Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform();
|
||||
ancestorUntransform.Invert();
|
||||
// asyncUntransform is LA.Inverse()
|
||||
gfx3DMatrix asyncUntransform = gfx::To3DMatrix(aApzc->GetCurrentAsyncTransform()).Inverse();
|
||||
Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransform();
|
||||
asyncUntransform.Invert();
|
||||
// nontransientAsyncTransform is LN
|
||||
gfx3DMatrix nontransientAsyncTransform = aApzc->GetNontransientAsyncTransform();
|
||||
Matrix4x4 nontransientAsyncTransform = aApzc->GetNontransientAsyncTransform();
|
||||
// transientAsyncUntransform is LT.Inverse()
|
||||
gfx3DMatrix transientAsyncUntransform = nontransientAsyncTransform * asyncUntransform;
|
||||
Matrix4x4 transientAsyncUntransform = nontransientAsyncTransform * asyncUntransform;
|
||||
|
||||
// aTransformToApzcOut is initialized to OC.Inverse() * NC.Inverse() * MC.Inverse() * LC.Inverse() * LN.Inverse()
|
||||
aTransformToApzcOut = ancestorUntransform * aApzc->GetCSSTransform().Inverse() * nontransientAsyncTransform.Inverse();
|
||||
Matrix4x4 cssUntransform = aApzc->GetCSSTransform();
|
||||
cssUntransform.Invert();
|
||||
Matrix4x4 nontransientAsyncUntransform = nontransientAsyncTransform;
|
||||
nontransientAsyncUntransform.Invert();
|
||||
aTransformToApzcOut = ancestorUntransform * cssUntransform * nontransientAsyncUntransform;
|
||||
// aTransformToGeckoOut is initialized to LT.Inverse() * LD * LC * MC * NC * OC
|
||||
aTransformToGeckoOut = transientAsyncUntransform * aApzc->GetTransformToLastDispatchedPaint() * aApzc->GetCSSTransform() * aApzc->GetAncestorTransform();
|
||||
|
||||
for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
|
||||
// ancestorUntransform is updated to RC.Inverse() * QC.Inverse() when parent == P
|
||||
ancestorUntransform = parent->GetAncestorTransform().Inverse();
|
||||
ancestorUntransform = parent->GetAncestorTransform();
|
||||
ancestorUntransform.Invert();
|
||||
// asyncUntransform is updated to PA.Inverse() when parent == P
|
||||
asyncUntransform = gfx::To3DMatrix(parent->GetCurrentAsyncTransform()).Inverse();
|
||||
asyncUntransform = parent->GetCurrentAsyncTransform();
|
||||
asyncUntransform.Invert();
|
||||
// untransformSinceLastApzc is RC.Inverse() * QC.Inverse() * PC.Inverse() * PA.Inverse()
|
||||
gfx3DMatrix untransformSinceLastApzc = ancestorUntransform * parent->GetCSSTransform().Inverse() * asyncUntransform;
|
||||
cssUntransform = parent->GetCSSTransform();
|
||||
cssUntransform.Invert();
|
||||
Matrix4x4 untransformSinceLastApzc = ancestorUntransform * cssUntransform * asyncUntransform;
|
||||
|
||||
// aTransformToApzcOut is RC.Inverse() * QC.Inverse() * PC.Inverse() * PA.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse() * LC.Inverse() * LN.Inverse()
|
||||
aTransformToApzcOut = untransformSinceLastApzc * aTransformToApzcOut;
|
||||
|
@ -10,10 +10,10 @@
|
||||
#include "FrameMetrics.h" // for FrameMetrics, etc
|
||||
#include "Units.h" // for CSSPoint, CSSRect, etc
|
||||
#include "gfxPoint.h" // for gfxPoint
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "mozilla/EventForwards.h" // for WidgetInputEvent, nsEventStatus
|
||||
#include "mozilla/Monitor.h" // for Monitor
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
@ -21,7 +21,6 @@
|
||||
#include "nsTArrayForwardDeclare.h" // for nsTArray, nsTArray_Impl, etc
|
||||
#include "mozilla/gfx/Logging.h" // for gfx::TreeLog
|
||||
|
||||
class gfx3DMatrix;
|
||||
class nsIntRegion;
|
||||
|
||||
namespace mozilla {
|
||||
@ -327,8 +326,8 @@ public:
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint,
|
||||
bool* aOutInOverscrolledApzc);
|
||||
void GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
|
||||
gfx3DMatrix& aTransformToGeckoOut);
|
||||
void GetInputTransforms(AsyncPanZoomController *aApzc, gfx::Matrix4x4& aTransformToApzcOut,
|
||||
gfx::Matrix4x4& aTransformToGeckoOut);
|
||||
private:
|
||||
/* Helpers */
|
||||
AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId);
|
||||
@ -358,7 +357,7 @@ private:
|
||||
*/
|
||||
AsyncPanZoomController* UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
Layer* aLayer, uint64_t aLayersId,
|
||||
gfx3DMatrix aTransform,
|
||||
gfx::Matrix4x4 aTransform,
|
||||
AsyncPanZoomController* aParent,
|
||||
AsyncPanZoomController* aNextSibling,
|
||||
bool aIsFirstPaint,
|
||||
@ -401,7 +400,7 @@ private:
|
||||
* but for some operations we need to use the initial transform.
|
||||
* Meaningless if mApzcForInputBlock is nullptr.
|
||||
*/
|
||||
gfx3DMatrix mCachedTransformToApzcForInputBlock;
|
||||
gfx::Matrix4x4 mCachedTransformToApzcForInputBlock;
|
||||
/* The chain of APZCs that will handle pans for the current touch input
|
||||
* block, in the order in which they will be scrolled. When one APZC has
|
||||
* been scrolled as far as it can, any overscroll will be handed off to
|
||||
|
@ -129,6 +129,8 @@ namespace layers {
|
||||
|
||||
typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior;
|
||||
typedef GeckoContentController::APZStateChange APZStateChange;
|
||||
typedef mozilla::gfx::Point Point;
|
||||
typedef mozilla::gfx::Matrix4x4 Matrix4x4;
|
||||
|
||||
/*
|
||||
* The following prefs are used to control the behaviour of the APZC.
|
||||
@ -1292,10 +1294,10 @@ AsyncPanZoomController::ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* aOut
|
||||
{
|
||||
APZCTreeManager* treeManagerLocal = mTreeManager;
|
||||
if (treeManagerLocal) {
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToGecko;
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko;
|
||||
treeManagerLocal->GetInputTransforms(this, transformToApzc, transformToGecko);
|
||||
gfxPoint result = transformToGecko.Transform(gfxPoint(aPoint.x, aPoint.y));
|
||||
Point result = transformToGecko * Point(aPoint.x, aPoint.y);
|
||||
// NOTE: This isn't *quite* LayoutDevicePoint, we just don't have a name
|
||||
// for this coordinate space and it maps the closest to LayoutDevicePoint.
|
||||
LayoutDevicePoint layoutPoint = LayoutDevicePoint(result.x, result.y);
|
||||
@ -2299,20 +2301,20 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
|
||||
/ mFrameMetrics.GetParentResolution());
|
||||
}
|
||||
|
||||
gfx3DMatrix AsyncPanZoomController::GetNontransientAsyncTransform() {
|
||||
Matrix4x4 AsyncPanZoomController::GetNontransientAsyncTransform() {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
return gfx3DMatrix::ScalingMatrix(mLastContentPaintMetrics.mResolution.scale,
|
||||
mLastContentPaintMetrics.mResolution.scale,
|
||||
1.0f);
|
||||
return Matrix4x4().Scale(mLastContentPaintMetrics.mResolution.scale,
|
||||
mLastContentPaintMetrics.mResolution.scale,
|
||||
1.0f);
|
||||
}
|
||||
|
||||
gfx3DMatrix AsyncPanZoomController::GetTransformToLastDispatchedPaint() {
|
||||
Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
LayerPoint scrollChange = (mLastContentPaintMetrics.GetScrollOffset() - mLastDispatchedPaintMetrics.GetScrollOffset())
|
||||
* mLastContentPaintMetrics.LayersPixelsPerCSSPixel();
|
||||
float zoomChange = mLastContentPaintMetrics.GetZoom().scale / mLastDispatchedPaintMetrics.GetZoom().scale;
|
||||
return gfx3DMatrix::Translation(scrollChange.x, scrollChange.y, 0) *
|
||||
gfx3DMatrix::ScalingMatrix(zoomChange, zoomChange, 1);
|
||||
return Matrix4x4().Translate(scrollChange.x, scrollChange.y, 0) *
|
||||
Matrix4x4().Scale(zoomChange, zoomChange, 1);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
|
||||
@ -2854,16 +2856,16 @@ void AsyncPanZoomController::ShareCompositorFrameMetrics() {
|
||||
|
||||
ParentLayerPoint AsyncPanZoomController::ToParentLayerCoords(const ScreenPoint& aPoint)
|
||||
{
|
||||
return TransformTo<ParentLayerPixel>(GetNontransientAsyncTransform() * GetCSSTransform(), aPoint);
|
||||
return TransformTo<ParentLayerPixel>(To3DMatrix(GetNontransientAsyncTransform() * GetCSSTransform()), aPoint);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::UpdateTransformScale()
|
||||
{
|
||||
gfx3DMatrix nontransientTransforms = GetNontransientAsyncTransform() * GetCSSTransform();
|
||||
if (!FuzzyEqualsMultiplicative(nontransientTransforms.GetXScale(), nontransientTransforms.GetYScale())) {
|
||||
Matrix4x4 nontransientTransforms = GetNontransientAsyncTransform() * GetCSSTransform();
|
||||
if (!FuzzyEqualsMultiplicative(nontransientTransforms._11, nontransientTransforms._22)) {
|
||||
NS_WARNING("The x- and y-scales of the nontransient transforms should be equal");
|
||||
}
|
||||
mFrameMetrics.mTransformScale.scale = nontransientTransforms.GetXScale();
|
||||
mFrameMetrics.mTransformScale.scale = nontransientTransforms._11;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "InputData.h"
|
||||
#include "Axis.h"
|
||||
#include "TaskThrottler.h"
|
||||
#include "gfx3DMatrix.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "nsRegion.h"
|
||||
|
||||
#include "base/message_loop.h"
|
||||
@ -69,6 +69,7 @@ class AsyncPanZoomController {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomController)
|
||||
|
||||
typedef mozilla::MonitorAutoLock MonitorAutoLock;
|
||||
typedef mozilla::gfx::Matrix4x4 Matrix4x4;
|
||||
typedef uint32_t TouchBehaviorFlags;
|
||||
|
||||
public:
|
||||
@ -221,9 +222,9 @@ public:
|
||||
/**
|
||||
* Returns the part of the async transform that will remain once Gecko does a
|
||||
* repaint at the desired metrics. That is, in the steady state:
|
||||
* gfx3DMatrix(GetCurrentAsyncTransform()) === GetNontransientAsyncTransform()
|
||||
* Matrix4x4(GetCurrentAsyncTransform()) === GetNontransientAsyncTransform()
|
||||
*/
|
||||
gfx3DMatrix GetNontransientAsyncTransform();
|
||||
Matrix4x4 GetNontransientAsyncTransform();
|
||||
|
||||
/**
|
||||
* Returns the transform to take something from the coordinate space of the
|
||||
@ -232,7 +233,7 @@ public:
|
||||
* processed, this is needed to transform input events properly into a space
|
||||
* gecko will understand.
|
||||
*/
|
||||
gfx3DMatrix GetTransformToLastDispatchedPaint();
|
||||
Matrix4x4 GetTransformToLastDispatchedPaint();
|
||||
|
||||
/**
|
||||
* Recalculates the displayport. Ideally, this should paint an area bigger
|
||||
@ -942,19 +943,19 @@ private:
|
||||
* hit-testing to see which APZC instance should handle touch events.
|
||||
*/
|
||||
public:
|
||||
void SetLayerHitTestData(const nsIntRegion& aRegion, const gfx3DMatrix& aTransformToLayer,
|
||||
const gfx3DMatrix& aTransformForLayer) {
|
||||
void SetLayerHitTestData(const nsIntRegion& aRegion, const Matrix4x4& aTransformToLayer,
|
||||
const Matrix4x4& aTransformForLayer) {
|
||||
mVisibleRegion = aRegion;
|
||||
mAncestorTransform = aTransformToLayer;
|
||||
mCSSTransform = aTransformForLayer;
|
||||
UpdateTransformScale();
|
||||
}
|
||||
|
||||
gfx3DMatrix GetAncestorTransform() const {
|
||||
Matrix4x4 GetAncestorTransform() const {
|
||||
return mAncestorTransform;
|
||||
}
|
||||
|
||||
gfx3DMatrix GetCSSTransform() const {
|
||||
Matrix4x4 GetCSSTransform() const {
|
||||
return mCSSTransform;
|
||||
}
|
||||
|
||||
@ -974,9 +975,9 @@ private:
|
||||
nsIntRegion mVisibleRegion;
|
||||
/* This is the cumulative CSS transform for all the layers between the parent
|
||||
* APZC and this one (not inclusive) */
|
||||
gfx3DMatrix mAncestorTransform;
|
||||
Matrix4x4 mAncestorTransform;
|
||||
/* This is the CSS transform for this APZC's layer. */
|
||||
gfx3DMatrix mCSSTransform;
|
||||
Matrix4x4 mCSSTransform;
|
||||
|
||||
|
||||
/* ===================================================================
|
||||
|
@ -676,7 +676,7 @@ ApplyAsyncTransformToScrollbarForContent(TimeStamp aCurrentFrame, ContainerLayer
|
||||
}
|
||||
|
||||
gfx3DMatrix asyncTransform = To3DMatrix(apzc->GetCurrentAsyncTransform());
|
||||
gfx3DMatrix nontransientTransform = apzc->GetNontransientAsyncTransform();
|
||||
gfx3DMatrix nontransientTransform = To3DMatrix(apzc->GetNontransientAsyncTransform());
|
||||
gfx3DMatrix transientTransform = asyncTransform * nontransientTransform.Inverse();
|
||||
|
||||
// |transientTransform| represents the amount by which we have scrolled and
|
||||
|
@ -1499,7 +1499,7 @@ SetScrollableFrameMetrics(Layer* aLayer, FrameMetrics::ViewID aScrollId,
|
||||
|
||||
static already_AddRefed<AsyncPanZoomController>
|
||||
GetTargetAPZC(APZCTreeManager* manager, const ScreenPoint& aPoint,
|
||||
gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToGeckoOut)
|
||||
Matrix4x4& aTransformToApzcOut, Matrix4x4& aTransformToGeckoOut)
|
||||
{
|
||||
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(aPoint, nullptr);
|
||||
if (hit) {
|
||||
@ -1520,15 +1520,15 @@ TEST_F(APZCTreeManagerTester, HitTesting1) {
|
||||
ScopedLayerTreeRegistration controller(0, root, mcc);
|
||||
|
||||
nsRefPtr<APZCTreeManager> manager = new TestAPZCTreeManager();
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToGecko;
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko;
|
||||
|
||||
// No APZC attached so hit testing will return no APZC at (20,20)
|
||||
nsRefPtr<AsyncPanZoomController> hit = GetTargetAPZC(manager, ScreenPoint(20, 20), transformToApzc, transformToGecko);
|
||||
AsyncPanZoomController* nullAPZC = nullptr;
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
EXPECT_EQ(gfx3DMatrix(), transformToApzc);
|
||||
EXPECT_EQ(gfx3DMatrix(), transformToGecko);
|
||||
EXPECT_EQ(Matrix4x4(), transformToApzc);
|
||||
EXPECT_EQ(Matrix4x4(), transformToGecko);
|
||||
|
||||
uint32_t paintSequenceNumber = 0;
|
||||
|
||||
@ -1538,8 +1538,8 @@ TEST_F(APZCTreeManagerTester, HitTesting1) {
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(15, 15)
|
||||
EXPECT_EQ(gfxPoint(15, 15), transformToApzc.Transform(gfxPoint(15, 15)));
|
||||
EXPECT_EQ(gfxPoint(15, 15), transformToGecko.Transform(gfxPoint(15, 15)));
|
||||
EXPECT_EQ(Point(15, 15), transformToApzc * Point(15, 15));
|
||||
EXPECT_EQ(Point(15, 15), transformToGecko * Point(15, 15));
|
||||
|
||||
// Now we have a sub APZC with a better fit
|
||||
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 1);
|
||||
@ -1548,8 +1548,8 @@ TEST_F(APZCTreeManagerTester, HitTesting1) {
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(25, 25)
|
||||
EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25)));
|
||||
EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(25, 25)));
|
||||
EXPECT_EQ(Point(25, 25), transformToApzc * Point(25, 25));
|
||||
EXPECT_EQ(Point(25, 25), transformToGecko * Point(25, 25));
|
||||
|
||||
// At this point, layers[4] obscures layers[3] at the point (15, 15) so
|
||||
// hitting there should hit the root APZC
|
||||
@ -1562,25 +1562,25 @@ TEST_F(APZCTreeManagerTester, HitTesting1) {
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(15, 15)
|
||||
EXPECT_EQ(gfxPoint(15, 15), transformToApzc.Transform(gfxPoint(15, 15)));
|
||||
EXPECT_EQ(gfxPoint(15, 15), transformToGecko.Transform(gfxPoint(15, 15)));
|
||||
EXPECT_EQ(Point(15, 15), transformToApzc * Point(15, 15));
|
||||
EXPECT_EQ(Point(15, 15), transformToGecko * Point(15, 15));
|
||||
|
||||
// Hit test ouside the reach of layer[3,4] but inside root
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(90, 90), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(90, 90)
|
||||
EXPECT_EQ(gfxPoint(90, 90), transformToApzc.Transform(gfxPoint(90, 90)));
|
||||
EXPECT_EQ(gfxPoint(90, 90), transformToGecko.Transform(gfxPoint(90, 90)));
|
||||
EXPECT_EQ(Point(90, 90), transformToApzc * Point(90, 90));
|
||||
EXPECT_EQ(Point(90, 90), transformToGecko * Point(90, 90));
|
||||
|
||||
// Hit test ouside the reach of any layer
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(1000, 10), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
EXPECT_EQ(gfx3DMatrix(), transformToApzc);
|
||||
EXPECT_EQ(gfx3DMatrix(), transformToGecko);
|
||||
EXPECT_EQ(Matrix4x4(), transformToApzc);
|
||||
EXPECT_EQ(Matrix4x4(), transformToGecko);
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(-1000, 10), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
EXPECT_EQ(gfx3DMatrix(), transformToApzc);
|
||||
EXPECT_EQ(gfx3DMatrix(), transformToGecko);
|
||||
EXPECT_EQ(Matrix4x4(), transformToApzc);
|
||||
EXPECT_EQ(Matrix4x4(), transformToGecko);
|
||||
|
||||
manager->ClearTree();
|
||||
}
|
||||
@ -1598,8 +1598,8 @@ TEST_F(APZCTreeManagerTester, HitTesting2) {
|
||||
|
||||
nsRefPtr<TestAPZCTreeManager> manager = new TestAPZCTreeManager();
|
||||
nsRefPtr<AsyncPanZoomController> hit;
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToGecko;
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko;
|
||||
|
||||
// Set a CSS transform on one of the layers.
|
||||
Matrix4x4 transform;
|
||||
@ -1626,8 +1626,8 @@ TEST_F(APZCTreeManagerTester, HitTesting2) {
|
||||
// Hit an area that's clearly on the root layer but not any of the child layers.
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(75, 25), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(apzcroot, hit.get());
|
||||
EXPECT_EQ(gfxPoint(75, 25), transformToApzc.Transform(gfxPoint(75, 25)));
|
||||
EXPECT_EQ(gfxPoint(75, 25), transformToGecko.Transform(gfxPoint(75, 25)));
|
||||
EXPECT_EQ(Point(75, 25), transformToApzc * Point(75, 25));
|
||||
EXPECT_EQ(Point(75, 25), transformToGecko * Point(75, 25));
|
||||
|
||||
// Hit an area on the root that would be on layers[3] if layers[2]
|
||||
// weren't transformed.
|
||||
@ -1638,31 +1638,31 @@ TEST_F(APZCTreeManagerTester, HitTesting2) {
|
||||
// start at x=10 but its content at x=20).
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(15, 75), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(apzcroot, hit.get());
|
||||
EXPECT_EQ(gfxPoint(15, 75), transformToApzc.Transform(gfxPoint(15, 75)));
|
||||
EXPECT_EQ(gfxPoint(15, 75), transformToGecko.Transform(gfxPoint(15, 75)));
|
||||
EXPECT_EQ(Point(15, 75), transformToApzc * Point(15, 75));
|
||||
EXPECT_EQ(Point(15, 75), transformToGecko * Point(15, 75));
|
||||
|
||||
// Hit an area on layers[1].
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(apzc1, hit.get());
|
||||
EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25)));
|
||||
EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(25, 25)));
|
||||
EXPECT_EQ(Point(25, 25), transformToApzc * Point(25, 25));
|
||||
EXPECT_EQ(Point(25, 25), transformToGecko * Point(25, 25));
|
||||
|
||||
// Hit an area on layers[3].
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(25, 75), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(apzc3, hit.get());
|
||||
// transformToApzc should unapply layers[2]'s transform
|
||||
EXPECT_EQ(gfxPoint(12.5, 75), transformToApzc.Transform(gfxPoint(25, 75)));
|
||||
EXPECT_EQ(Point(12.5, 75), transformToApzc * Point(25, 75));
|
||||
// and transformToGecko should reapply it
|
||||
EXPECT_EQ(gfxPoint(25, 75), transformToGecko.Transform(gfxPoint(12.5, 75)));
|
||||
EXPECT_EQ(Point(25, 75), transformToGecko * Point(12.5, 75));
|
||||
|
||||
// Hit an area on layers[3] that would be on the root if layers[2]
|
||||
// weren't transformed.
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(apzc3, hit.get());
|
||||
// transformToApzc should unapply layers[2]'s transform
|
||||
EXPECT_EQ(gfxPoint(37.5, 75), transformToApzc.Transform(gfxPoint(75, 75)));
|
||||
EXPECT_EQ(Point(37.5, 75), transformToApzc * Point(75, 75));
|
||||
// and transformToGecko should reapply it
|
||||
EXPECT_EQ(gfxPoint(75, 75), transformToGecko.Transform(gfxPoint(37.5, 75)));
|
||||
EXPECT_EQ(Point(75, 75), transformToGecko * Point(37.5, 75));
|
||||
|
||||
// Pan the root layer upward by 50 pixels.
|
||||
// This causes layers[1] to scroll out of view, and an async transform
|
||||
@ -1684,21 +1684,21 @@ TEST_F(APZCTreeManagerTester, HitTesting2) {
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(apzcroot, hit.get());
|
||||
// transformToApzc doesn't unapply the root's own async transform
|
||||
EXPECT_EQ(gfxPoint(75, 75), transformToApzc.Transform(gfxPoint(75, 75)));
|
||||
EXPECT_EQ(Point(75, 75), transformToApzc * Point(75, 75));
|
||||
// and transformToGecko unapplies it and then reapplies it, because by the
|
||||
// time the event being transformed reaches Gecko the new paint request will
|
||||
// have been handled.
|
||||
EXPECT_EQ(gfxPoint(75, 75), transformToGecko.Transform(gfxPoint(75, 75)));
|
||||
EXPECT_EQ(Point(75, 75), transformToGecko * Point(75, 75));
|
||||
|
||||
// Hit where layers[1] used to be and where layers[3] should now be.
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(apzc3, hit.get());
|
||||
// transformToApzc unapplies both layers[2]'s css transform and the root's
|
||||
// async transform
|
||||
EXPECT_EQ(gfxPoint(12.5, 75), transformToApzc.Transform(gfxPoint(25, 25)));
|
||||
EXPECT_EQ(Point(12.5, 75), transformToApzc * Point(25, 25));
|
||||
// transformToGecko reapplies both the css transform and the async transform
|
||||
// because we have already issued a paint request with it.
|
||||
EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(12.5, 75)));
|
||||
EXPECT_EQ(Point(25, 25), transformToGecko * Point(12.5, 75));
|
||||
|
||||
// This second pan will move the APZC by another 50 pixels but since the paint
|
||||
// request dispatched above has not "completed", we will not dispatch another
|
||||
@ -1712,19 +1712,19 @@ TEST_F(APZCTreeManagerTester, HitTesting2) {
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(apzcroot, hit.get());
|
||||
// transformToApzc doesn't unapply the root's own async transform
|
||||
EXPECT_EQ(gfxPoint(75, 75), transformToApzc.Transform(gfxPoint(75, 75)));
|
||||
EXPECT_EQ(Point(75, 75), transformToApzc * Point(75, 75));
|
||||
// transformToGecko unapplies the full async transform of -100 pixels, and then
|
||||
// reapplies the "D" transform of -50 leading to an overall adjustment of +50
|
||||
EXPECT_EQ(gfxPoint(75, 125), transformToGecko.Transform(gfxPoint(75, 75)));
|
||||
EXPECT_EQ(Point(75, 125), transformToGecko * Point(75, 75));
|
||||
|
||||
// Hit where layers[1] used to be. It should now hit the root.
|
||||
hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
|
||||
EXPECT_EQ(apzcroot, hit.get());
|
||||
// transformToApzc doesn't unapply the root's own async transform
|
||||
EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25)));
|
||||
EXPECT_EQ(Point(25, 25), transformToApzc * Point(25, 25));
|
||||
// transformToGecko unapplies the full async transform of -100 pixels, and then
|
||||
// reapplies the "D" transform of -50 leading to an overall adjustment of +50
|
||||
EXPECT_EQ(gfxPoint(25, 75), transformToGecko.Transform(gfxPoint(25, 25)));
|
||||
EXPECT_EQ(Point(25, 75), transformToGecko * Point(25, 25));
|
||||
|
||||
manager->ClearTree();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user