APZTestData.h (9852B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_layers_APZTestData_h 8 #define mozilla_layers_APZTestData_h 9 10 #include <map> 11 12 #include "nsDebug.h" // for NS_WARNING 13 #include "nsDOMNavigationTiming.h" // for DOMHighResTimeStamp 14 #include "nsTArray.h" 15 #include "mozilla/Assertions.h" // for MOZ_ASSERT 16 #include "mozilla/DebugOnly.h" // for DebugOnly 17 #include "mozilla/GfxMessageUtils.h" // for ParamTraits specializations 18 #include "mozilla/StaticPrefs_apz.h" 19 #include "mozilla/ToString.h" // for ToString 20 #include "mozilla/gfx/CompositorHitTestInfo.h" 21 #include "mozilla/layers/LayersMessageUtils.h" // for ParamTraits specializations 22 #include "mozilla/layers/ScrollableLayerGuid.h" 23 #include "ipc/IPCMessageUtils.h" 24 #include "js/TypeDecls.h" 25 26 namespace mozilla { 27 namespace layers { 28 29 typedef uint32_t SequenceNumber; 30 31 /** 32 * This structure is used to store information logged by various gecko 33 * components for later examination by test code. 34 * It contains a bucket for every paint (initiated on the client side), 35 * and every repaint request (initiated on the compositor side by 36 * AsyncPanZoomController::RequestContentRepait), which are identified by 37 * sequence numbers, and within that, a set of arbitrary string key/value 38 * pairs for every scrollable frame, identified by a scroll id. 39 * There are two instances of this data structure for every content thread: 40 * one on the client side and one of the compositor side. 41 * It also contains a list of hit-test results for MozMouseHittest events 42 * dispatched during testing. This list is only populated on the compositor 43 * instance of this class. 44 */ 45 // TODO(botond): 46 // - Improve warnings/asserts. 47 // - Add ability to associate a repaint request triggered during a layers 48 // update with the sequence number of the paint that caused the layers 49 // update. 50 class APZTestData { 51 typedef ScrollableLayerGuid::ViewID ViewID; 52 friend struct IPC::ParamTraits<APZTestData>; 53 friend struct APZTestDataToJSConverter; 54 55 public: 56 void StartNewPaint(SequenceNumber aSequenceNumber) { 57 // We should never get more than one paint with the same sequence number. 58 MOZ_ASSERT(mPaints.find(aSequenceNumber) == mPaints.end()); 59 mPaints.insert(DataStore::value_type(aSequenceNumber, Bucket())); 60 } 61 void LogTestDataForPaint(SequenceNumber aSequenceNumber, ViewID aScrollId, 62 const std::string& aKey, const std::string& aValue) { 63 LogTestDataImpl(mPaints, aSequenceNumber, aScrollId, aKey, aValue); 64 } 65 66 void StartNewRepaintRequest(SequenceNumber aSequenceNumber) { 67 typedef std::pair<DataStore::iterator, bool> InsertResultT; 68 DebugOnly<InsertResultT> insertResult = mRepaintRequests.insert( 69 DataStore::value_type(aSequenceNumber, Bucket())); 70 MOZ_ASSERT(((InsertResultT&)insertResult).second, 71 "Already have a repaint request with this sequence number"); 72 } 73 void LogTestDataForRepaintRequest(SequenceNumber aSequenceNumber, 74 ViewID aScrollId, const std::string& aKey, 75 const std::string& aValue) { 76 LogTestDataImpl(mRepaintRequests, aSequenceNumber, aScrollId, aKey, aValue); 77 } 78 void RecordHitResult(const ScreenPoint& aPoint, 79 const mozilla::gfx::CompositorHitTestInfo& aResult, 80 const LayersId& aLayersId, const ViewID& aScrollId) { 81 mHitResults.AppendElement(HitResult{aPoint, aResult, aLayersId, aScrollId}); 82 } 83 void RecordSampledResult(const CSSPoint& aScrollOffset, 84 DOMHighResTimeStamp aSampledTimeStamp, 85 const LayersId& aLayersId, const ViewID& aScrollId) { 86 mSampledResults.AppendElement( 87 SampledResult{aScrollOffset, aSampledTimeStamp, aLayersId, aScrollId}); 88 } 89 void RecordAdditionalData(const std::string& aKey, 90 const std::string& aValue) { 91 mAdditionalData[aKey] = aValue; 92 } 93 94 // Convert this object to a JS representation. 95 bool ToJS(JS::MutableHandle<JS::Value> aOutValue, JSContext* aContext) const; 96 97 // Use dummy derived structures wrapping the typedefs to work around a type 98 // name length limit in MSVC. 99 typedef std::map<std::string, std::string> ScrollFrameDataBase; 100 struct ScrollFrameData : ScrollFrameDataBase {}; 101 typedef std::map<ViewID, ScrollFrameData> BucketBase; 102 struct Bucket : BucketBase {}; 103 typedef std::map<SequenceNumber, Bucket> DataStoreBase; 104 struct DataStore : DataStoreBase {}; 105 struct HitResult { 106 ScreenPoint point; 107 mozilla::gfx::CompositorHitTestInfo result; 108 LayersId layersId; 109 ViewID scrollId; 110 }; 111 struct SampledResult { 112 CSSPoint scrollOffset; 113 DOMHighResTimeStamp sampledTimeStamp; 114 LayersId layersId; 115 ViewID scrollId; 116 }; 117 118 private: 119 DataStore mPaints; 120 DataStore mRepaintRequests; 121 CopyableTArray<HitResult> mHitResults; 122 CopyableTArray<SampledResult> mSampledResults; 123 // Additional free-form data that's not grouped paint or scroll frame. 124 std::map<std::string, std::string> mAdditionalData; 125 126 void LogTestDataImpl(DataStore& aDataStore, SequenceNumber aSequenceNumber, 127 ViewID aScrollId, const std::string& aKey, 128 const std::string& aValue) { 129 auto bucketIterator = aDataStore.find(aSequenceNumber); 130 if (bucketIterator == aDataStore.end()) { 131 MOZ_ASSERT(false, 132 "LogTestDataImpl called with nonexistent sequence number"); 133 return; 134 } 135 Bucket& bucket = bucketIterator->second; 136 ScrollFrameData& scrollFrameData = 137 bucket[aScrollId]; // create if doesn't exist 138 MOZ_ASSERT(scrollFrameData.find(aKey) == scrollFrameData.end() || 139 scrollFrameData[aKey] == aValue); 140 scrollFrameData.insert(ScrollFrameData::value_type(aKey, aValue)); 141 } 142 }; 143 144 // A helper class for logging data for a paint. 145 class APZPaintLogHelper { 146 public: 147 APZPaintLogHelper(APZTestData* aTestData, SequenceNumber aPaintSequenceNumber, 148 bool aIsTestLoggingEnabled) 149 : mTestData(aTestData), mPaintSequenceNumber(aPaintSequenceNumber) { 150 MOZ_ASSERT(!aTestData || aIsTestLoggingEnabled, "don't call me"); 151 } 152 153 template <typename Value> 154 void LogTestData(ScrollableLayerGuid::ViewID aScrollId, 155 const std::string& aKey, const Value& aValue) const { 156 if (mTestData) { // avoid stringifying if mTestData == nullptr 157 LogTestData(aScrollId, aKey, ToString(aValue)); 158 } 159 } 160 161 void LogTestData(ScrollableLayerGuid::ViewID aScrollId, 162 const std::string& aKey, const std::string& aValue) const { 163 if (mTestData) { 164 mTestData->LogTestDataForPaint(mPaintSequenceNumber, aScrollId, aKey, 165 aValue); 166 } 167 } 168 169 private: 170 APZTestData* mTestData; 171 SequenceNumber mPaintSequenceNumber; 172 }; 173 174 } // namespace layers 175 } // namespace mozilla 176 177 namespace IPC { 178 179 template <> 180 struct ParamTraits<mozilla::layers::APZTestData> { 181 typedef mozilla::layers::APZTestData paramType; 182 183 static void Write(MessageWriter* aWriter, const paramType& aParam) { 184 WriteParam(aWriter, aParam.mPaints); 185 WriteParam(aWriter, aParam.mRepaintRequests); 186 WriteParam(aWriter, aParam.mHitResults); 187 WriteParam(aWriter, aParam.mSampledResults); 188 WriteParam(aWriter, aParam.mAdditionalData); 189 } 190 191 static bool Read(MessageReader* aReader, paramType* aResult) { 192 return (ReadParam(aReader, &aResult->mPaints) && 193 ReadParam(aReader, &aResult->mRepaintRequests) && 194 ReadParam(aReader, &aResult->mHitResults) && 195 ReadParam(aReader, &aResult->mSampledResults) && 196 ReadParam(aReader, &aResult->mAdditionalData)); 197 } 198 }; 199 200 template <> 201 struct ParamTraits<mozilla::layers::APZTestData::ScrollFrameData> 202 : ParamTraits<mozilla::layers::APZTestData::ScrollFrameDataBase> {}; 203 204 template <> 205 struct ParamTraits<mozilla::layers::APZTestData::Bucket> 206 : ParamTraits<mozilla::layers::APZTestData::BucketBase> {}; 207 208 template <> 209 struct ParamTraits<mozilla::layers::APZTestData::DataStore> 210 : ParamTraits<mozilla::layers::APZTestData::DataStoreBase> {}; 211 212 template <> 213 struct ParamTraits<mozilla::layers::APZTestData::HitResult> { 214 typedef mozilla::layers::APZTestData::HitResult paramType; 215 216 static void Write(MessageWriter* aWriter, const paramType& aParam) { 217 WriteParam(aWriter, aParam.point); 218 WriteParam(aWriter, aParam.result); 219 WriteParam(aWriter, aParam.layersId); 220 WriteParam(aWriter, aParam.scrollId); 221 } 222 223 static bool Read(MessageReader* aReader, paramType* aResult) { 224 return (ReadParam(aReader, &aResult->point) && 225 ReadParam(aReader, &aResult->result) && 226 ReadParam(aReader, &aResult->layersId) && 227 ReadParam(aReader, &aResult->scrollId)); 228 } 229 }; 230 231 template <> 232 struct ParamTraits<mozilla::layers::APZTestData::SampledResult> { 233 typedef mozilla::layers::APZTestData::SampledResult paramType; 234 235 static void Write(MessageWriter* aWriter, const paramType& aParam) { 236 WriteParam(aWriter, aParam.scrollOffset); 237 WriteParam(aWriter, aParam.sampledTimeStamp); 238 WriteParam(aWriter, aParam.layersId); 239 WriteParam(aWriter, aParam.scrollId); 240 } 241 242 static bool Read(MessageReader* aReader, paramType* aResult) { 243 return (ReadParam(aReader, &aResult->scrollOffset) && 244 ReadParam(aReader, &aResult->sampledTimeStamp) && 245 ReadParam(aReader, &aResult->layersId) && 246 ReadParam(aReader, &aResult->scrollId)); 247 } 248 }; 249 250 } // namespace IPC 251 252 #endif /* mozilla_layers_APZTestData_h */