252 lines
9.6 KiB
C++
252 lines
9.6 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef mozilla_layers_APZTestData_h
|
|
#define mozilla_layers_APZTestData_h
|
|
|
|
#include <map>
|
|
|
|
#include "nsDebug.h" // for NS_WARNING
|
|
#include "nsDOMNavigationTiming.h" // for DOMHighResTimeStamp
|
|
#include "nsTArray.h"
|
|
#include "mozilla/Assertions.h" // for MOZ_ASSERT
|
|
#include "mozilla/DebugOnly.h" // for DebugOnly
|
|
#include "mozilla/GfxMessageUtils.h" // for ParamTraits specializations
|
|
#include "mozilla/StaticPrefs_apz.h"
|
|
#include "mozilla/ToString.h" // for ToString
|
|
#include "mozilla/gfx/CompositorHitTestInfo.h"
|
|
#include "mozilla/layers/LayersMessageUtils.h" // for ParamTraits specializations
|
|
#include "mozilla/layers/ScrollableLayerGuid.h"
|
|
#include "ipc/IPCMessageUtils.h"
|
|
#include "js/TypeDecls.h"
|
|
|
|
namespace mozilla {
|
|
namespace layers {
|
|
|
|
typedef uint32_t SequenceNumber;
|
|
|
|
/**
|
|
* This structure is used to store information logged by various gecko
|
|
* components for later examination by test code.
|
|
* It contains a bucket for every paint (initiated on the client side),
|
|
* and every repaint request (initiated on the compositor side by
|
|
* AsyncPanZoomController::RequestContentRepait), which are identified by
|
|
* sequence numbers, and within that, a set of arbitrary string key/value
|
|
* pairs for every scrollable frame, identified by a scroll id.
|
|
* There are two instances of this data structure for every content thread:
|
|
* one on the client side and one of the compositor side.
|
|
* It also contains a list of hit-test results for MozMouseHittest events
|
|
* dispatched during testing. This list is only populated on the compositor
|
|
* instance of this class.
|
|
*/
|
|
// TODO(botond):
|
|
// - Improve warnings/asserts.
|
|
// - Add ability to associate a repaint request triggered during a layers
|
|
// update with the sequence number of the paint that caused the layers
|
|
// update.
|
|
class APZTestData {
|
|
typedef ScrollableLayerGuid::ViewID ViewID;
|
|
friend struct IPC::ParamTraits<APZTestData>;
|
|
friend struct APZTestDataToJSConverter;
|
|
|
|
public:
|
|
void StartNewPaint(SequenceNumber aSequenceNumber) {
|
|
// We should never get more than one paint with the same sequence number.
|
|
MOZ_ASSERT(mPaints.find(aSequenceNumber) == mPaints.end());
|
|
mPaints.insert(DataStore::value_type(aSequenceNumber, Bucket()));
|
|
}
|
|
void LogTestDataForPaint(SequenceNumber aSequenceNumber, ViewID aScrollId,
|
|
const std::string& aKey, const std::string& aValue) {
|
|
LogTestDataImpl(mPaints, aSequenceNumber, aScrollId, aKey, aValue);
|
|
}
|
|
|
|
void StartNewRepaintRequest(SequenceNumber aSequenceNumber) {
|
|
typedef std::pair<DataStore::iterator, bool> InsertResultT;
|
|
DebugOnly<InsertResultT> insertResult = mRepaintRequests.insert(
|
|
DataStore::value_type(aSequenceNumber, Bucket()));
|
|
MOZ_ASSERT(((InsertResultT&)insertResult).second,
|
|
"Already have a repaint request with this sequence number");
|
|
}
|
|
void LogTestDataForRepaintRequest(SequenceNumber aSequenceNumber,
|
|
ViewID aScrollId, const std::string& aKey,
|
|
const std::string& aValue) {
|
|
LogTestDataImpl(mRepaintRequests, aSequenceNumber, aScrollId, aKey, aValue);
|
|
}
|
|
void RecordHitResult(const ScreenPoint& aPoint,
|
|
const mozilla::gfx::CompositorHitTestInfo& aResult,
|
|
const LayersId& aLayersId, const ViewID& aScrollId) {
|
|
mHitResults.AppendElement(HitResult{aPoint, aResult, aLayersId, aScrollId});
|
|
}
|
|
void RecordSampledResult(const CSSPoint& aScrollOffset,
|
|
DOMHighResTimeStamp aSampledTimeStamp,
|
|
const LayersId& aLayersId, const ViewID& aScrollId) {
|
|
mSampledResults.AppendElement(
|
|
SampledResult{aScrollOffset, aSampledTimeStamp, aLayersId, aScrollId});
|
|
}
|
|
void RecordAdditionalData(const std::string& aKey,
|
|
const std::string& aValue) {
|
|
mAdditionalData[aKey] = aValue;
|
|
}
|
|
|
|
// Convert this object to a JS representation.
|
|
bool ToJS(JS::MutableHandle<JS::Value> aOutValue, JSContext* aContext) const;
|
|
|
|
// Use dummy derived structures wrapping the typedefs to work around a type
|
|
// name length limit in MSVC.
|
|
typedef std::map<std::string, std::string> ScrollFrameDataBase;
|
|
struct ScrollFrameData : ScrollFrameDataBase {};
|
|
typedef std::map<ViewID, ScrollFrameData> BucketBase;
|
|
struct Bucket : BucketBase {};
|
|
typedef std::map<SequenceNumber, Bucket> DataStoreBase;
|
|
struct DataStore : DataStoreBase {};
|
|
struct HitResult {
|
|
ScreenPoint point;
|
|
mozilla::gfx::CompositorHitTestInfo result;
|
|
LayersId layersId;
|
|
ViewID scrollId;
|
|
};
|
|
struct SampledResult {
|
|
CSSPoint scrollOffset;
|
|
DOMHighResTimeStamp sampledTimeStamp;
|
|
LayersId layersId;
|
|
ViewID scrollId;
|
|
};
|
|
|
|
private:
|
|
DataStore mPaints;
|
|
DataStore mRepaintRequests;
|
|
CopyableTArray<HitResult> mHitResults;
|
|
CopyableTArray<SampledResult> mSampledResults;
|
|
// Additional free-form data that's not grouped paint or scroll frame.
|
|
std::map<std::string, std::string> mAdditionalData;
|
|
|
|
void LogTestDataImpl(DataStore& aDataStore, SequenceNumber aSequenceNumber,
|
|
ViewID aScrollId, const std::string& aKey,
|
|
const std::string& aValue) {
|
|
auto bucketIterator = aDataStore.find(aSequenceNumber);
|
|
if (bucketIterator == aDataStore.end()) {
|
|
MOZ_ASSERT(false,
|
|
"LogTestDataImpl called with nonexistent sequence number");
|
|
return;
|
|
}
|
|
Bucket& bucket = bucketIterator->second;
|
|
ScrollFrameData& scrollFrameData =
|
|
bucket[aScrollId]; // create if doesn't exist
|
|
MOZ_ASSERT(scrollFrameData.find(aKey) == scrollFrameData.end() ||
|
|
scrollFrameData[aKey] == aValue);
|
|
scrollFrameData.insert(ScrollFrameData::value_type(aKey, aValue));
|
|
}
|
|
};
|
|
|
|
// A helper class for logging data for a paint.
|
|
class APZPaintLogHelper {
|
|
public:
|
|
APZPaintLogHelper(APZTestData* aTestData, SequenceNumber aPaintSequenceNumber,
|
|
bool aIsTestLoggingEnabled)
|
|
: mTestData(aTestData), mPaintSequenceNumber(aPaintSequenceNumber) {
|
|
MOZ_ASSERT(!aTestData || aIsTestLoggingEnabled, "don't call me");
|
|
}
|
|
|
|
template <typename Value>
|
|
void LogTestData(ScrollableLayerGuid::ViewID aScrollId,
|
|
const std::string& aKey, const Value& aValue) const {
|
|
if (mTestData) { // avoid stringifying if mTestData == nullptr
|
|
LogTestData(aScrollId, aKey, ToString(aValue));
|
|
}
|
|
}
|
|
|
|
void LogTestData(ScrollableLayerGuid::ViewID aScrollId,
|
|
const std::string& aKey, const std::string& aValue) const {
|
|
if (mTestData) {
|
|
mTestData->LogTestDataForPaint(mPaintSequenceNumber, aScrollId, aKey,
|
|
aValue);
|
|
}
|
|
}
|
|
|
|
private:
|
|
APZTestData* mTestData;
|
|
SequenceNumber mPaintSequenceNumber;
|
|
};
|
|
|
|
} // namespace layers
|
|
} // namespace mozilla
|
|
|
|
namespace IPC {
|
|
|
|
template <>
|
|
struct ParamTraits<mozilla::layers::APZTestData> {
|
|
typedef mozilla::layers::APZTestData paramType;
|
|
|
|
static void Write(MessageWriter* aWriter, const paramType& aParam) {
|
|
WriteParam(aWriter, aParam.mPaints);
|
|
WriteParam(aWriter, aParam.mRepaintRequests);
|
|
WriteParam(aWriter, aParam.mHitResults);
|
|
WriteParam(aWriter, aParam.mSampledResults);
|
|
WriteParam(aWriter, aParam.mAdditionalData);
|
|
}
|
|
|
|
static bool Read(MessageReader* aReader, paramType* aResult) {
|
|
return (ReadParam(aReader, &aResult->mPaints) &&
|
|
ReadParam(aReader, &aResult->mRepaintRequests) &&
|
|
ReadParam(aReader, &aResult->mHitResults) &&
|
|
ReadParam(aReader, &aResult->mSampledResults) &&
|
|
ReadParam(aReader, &aResult->mAdditionalData));
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct ParamTraits<mozilla::layers::APZTestData::ScrollFrameData>
|
|
: ParamTraits<mozilla::layers::APZTestData::ScrollFrameDataBase> {};
|
|
|
|
template <>
|
|
struct ParamTraits<mozilla::layers::APZTestData::Bucket>
|
|
: ParamTraits<mozilla::layers::APZTestData::BucketBase> {};
|
|
|
|
template <>
|
|
struct ParamTraits<mozilla::layers::APZTestData::DataStore>
|
|
: ParamTraits<mozilla::layers::APZTestData::DataStoreBase> {};
|
|
|
|
template <>
|
|
struct ParamTraits<mozilla::layers::APZTestData::HitResult> {
|
|
typedef mozilla::layers::APZTestData::HitResult paramType;
|
|
|
|
static void Write(MessageWriter* aWriter, const paramType& aParam) {
|
|
WriteParam(aWriter, aParam.point);
|
|
WriteParam(aWriter, aParam.result);
|
|
WriteParam(aWriter, aParam.layersId);
|
|
WriteParam(aWriter, aParam.scrollId);
|
|
}
|
|
|
|
static bool Read(MessageReader* aReader, paramType* aResult) {
|
|
return (ReadParam(aReader, &aResult->point) &&
|
|
ReadParam(aReader, &aResult->result) &&
|
|
ReadParam(aReader, &aResult->layersId) &&
|
|
ReadParam(aReader, &aResult->scrollId));
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct ParamTraits<mozilla::layers::APZTestData::SampledResult> {
|
|
typedef mozilla::layers::APZTestData::SampledResult paramType;
|
|
|
|
static void Write(MessageWriter* aWriter, const paramType& aParam) {
|
|
WriteParam(aWriter, aParam.scrollOffset);
|
|
WriteParam(aWriter, aParam.sampledTimeStamp);
|
|
WriteParam(aWriter, aParam.layersId);
|
|
WriteParam(aWriter, aParam.scrollId);
|
|
}
|
|
|
|
static bool Read(MessageReader* aReader, paramType* aResult) {
|
|
return (ReadParam(aReader, &aResult->scrollOffset) &&
|
|
ReadParam(aReader, &aResult->sampledTimeStamp) &&
|
|
ReadParam(aReader, &aResult->layersId) &&
|
|
ReadParam(aReader, &aResult->scrollId));
|
|
}
|
|
};
|
|
|
|
} // namespace IPC
|
|
|
|
#endif /* mozilla_layers_APZTestData_h */
|