diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/layers/apz/testutil/APZTestData.h | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/gfx/layers/apz/testutil/APZTestData.h b/gfx/layers/apz/testutil/APZTestData.h new file mode 100644 index 0000000000..e4a73c80cc --- /dev/null +++ b/gfx/layers/apz/testutil/APZTestData.h @@ -0,0 +1,252 @@ +/* -*- 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) + : mTestData(aTestData), mPaintSequenceNumber(aPaintSequenceNumber) { + MOZ_ASSERT(!aTestData || StaticPrefs::apz_test_logging_enabled(), + "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 */ |