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_GFX_DRAWEVENTRECORDER_H_ 8 #define MOZILLA_GFX_DRAWEVENTRECORDER_H_ 9 10 #include "2D.h" 11 #include "RecordedEvent.h" 12 #include "RecordingTypes.h" 13 14 #include <unordered_set> 15 #include <unordered_map> 16 #include <functional> 17 18 #include "nsTHashSet.h" 19 20 namespace mozilla { 21 namespace gfx { 22 23 class PathRecording; 24 25 class DrawEventRecorderPrivate : public DrawEventRecorder { 26 public: 27 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPrivate, override) 28 29 DrawEventRecorderPrivate(); 30 virtual ~DrawEventRecorderPrivate() = default; Finish()31 bool Finish() override { 32 ClearResources(); 33 return true; 34 } FlushItem(IntRect)35 virtual void FlushItem(IntRect) {} DetachResources()36 void DetachResources() { 37 // The iteration is a bit awkward here because our iterator will 38 // be invalidated by the removal 39 for (auto font = mStoredFonts.begin(); font != mStoredFonts.end();) { 40 auto oldFont = font++; 41 (*oldFont)->RemoveUserData(reinterpret_cast<UserDataKey*>(this)); 42 } 43 for (auto surface = mStoredSurfaces.begin(); 44 surface != mStoredSurfaces.end();) { 45 auto oldSurface = surface++; 46 (*oldSurface)->RemoveUserData(reinterpret_cast<UserDataKey*>(this)); 47 } 48 mStoredFonts.clear(); 49 mStoredSurfaces.clear(); 50 } 51 ClearResources()52 void ClearResources() { 53 mStoredObjects.clear(); 54 mStoredFontData.clear(); 55 mScaledFonts.clear(); 56 } 57 58 template <class S> WriteHeader(S & aStream)59 void WriteHeader(S& aStream) { 60 WriteElement(aStream, kMagicInt); 61 WriteElement(aStream, kMajorRevision); 62 WriteElement(aStream, kMinorRevision); 63 } 64 65 virtual void RecordEvent(const RecordedEvent& aEvent) = 0; 66 void WritePath(const PathRecording* aPath); 67 AddStoredObject(const ReferencePtr aObject)68 void AddStoredObject(const ReferencePtr aObject) { 69 mStoredObjects.insert(aObject); 70 } 71 RemoveStoredObject(const ReferencePtr aObject)72 void RemoveStoredObject(const ReferencePtr aObject) { 73 mStoredObjects.erase(aObject); 74 } 75 76 /** 77 * @param aUnscaledFont the UnscaledFont to increment the reference count for 78 * @return the previous reference count 79 */ IncrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont)80 int32_t IncrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont) { 81 int32_t& count = mUnscaledFontRefs[aUnscaledFont]; 82 return count++; 83 } 84 85 /** 86 * Decrements the reference count for aUnscaledFont and, if count is now zero, 87 * records its destruction. 88 * @param aUnscaledFont the UnscaledFont to decrement the reference count for 89 */ 90 void DecrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont); 91 AddScaledFont(ScaledFont * aFont)92 void AddScaledFont(ScaledFont* aFont) { 93 if (mStoredFonts.insert(aFont).second && WantsExternalFonts()) { 94 mScaledFonts.push_back(aFont); 95 } 96 } 97 RemoveScaledFont(ScaledFont * aFont)98 void RemoveScaledFont(ScaledFont* aFont) { mStoredFonts.erase(aFont); } 99 AddSourceSurface(SourceSurface * aSurface)100 void AddSourceSurface(SourceSurface* aSurface) { 101 mStoredSurfaces.insert(aSurface); 102 } 103 RemoveSourceSurface(SourceSurface * aSurface)104 void RemoveSourceSurface(SourceSurface* aSurface) { 105 mStoredSurfaces.erase(aSurface); 106 } 107 HasStoredObject(const ReferencePtr aObject)108 bool HasStoredObject(const ReferencePtr aObject) { 109 return mStoredObjects.find(aObject) != mStoredObjects.end(); 110 } 111 AddStoredFontData(const uint64_t aFontDataKey)112 void AddStoredFontData(const uint64_t aFontDataKey) { 113 mStoredFontData.insert(aFontDataKey); 114 } 115 HasStoredFontData(const uint64_t aFontDataKey)116 bool HasStoredFontData(const uint64_t aFontDataKey) { 117 return mStoredFontData.find(aFontDataKey) != mStoredFontData.end(); 118 } 119 WantsExternalFonts()120 bool WantsExternalFonts() const { return mExternalFonts; } 121 TakeExternalSurfaces(std::vector<RefPtr<SourceSurface>> & aSurfaces)122 void TakeExternalSurfaces(std::vector<RefPtr<SourceSurface>>& aSurfaces) { 123 aSurfaces = std::move(mExternalSurfaces); 124 } 125 126 virtual void StoreSourceSurfaceRecording(SourceSurface* aSurface, 127 const char* aReason); 128 129 /** 130 * This is virtual to allow subclasses to control the recording, if for 131 * example it needs to happen on a specific thread. aSurface is a void* 132 * instead of a SourceSurface* because this is called during the SourceSurface 133 * destructor, so it is partially destructed and should not be accessed. If we 134 * use a SourceSurface* we might, for example, accidentally AddRef/Release the 135 * object by passing it to NewRunnableMethod to submit to a different thread. 136 * We are only using the pointer as a lookup ID to our internal maps and 137 * ReferencePtr to be used on the translation side. 138 * @param aSurface the surface whose destruction is being recorded 139 */ 140 virtual void RecordSourceSurfaceDestruction(void* aSurface); 141 AddDependentSurface(uint64_t aDependencyId)142 virtual void AddDependentSurface(uint64_t aDependencyId) { 143 MOZ_CRASH("GFX: AddDependentSurface"); 144 } 145 146 protected: 147 void StoreExternalSurfaceRecording(SourceSurface* aSurface, uint64_t aKey); 148 149 virtual void Flush() = 0; 150 151 std::unordered_set<const void*> mStoredObjects; 152 153 // It's difficult to track the lifetimes of UnscaledFonts directly, so we 154 // instead track the number of recorded ScaledFonts that hold a reference to 155 // an Unscaled font and use that as a proxy to the real lifetime. An 156 // UnscaledFonts lifetime could be longer than this, but we only use the 157 // ScaledFonts directly and if another uses an UnscaledFont we have destroyed 158 // on the translation side, it will be recreated. 159 std::unordered_map<const void*, int32_t> mUnscaledFontRefs; 160 161 std::unordered_set<uint64_t> mStoredFontData; 162 std::unordered_set<ScaledFont*> mStoredFonts; 163 std::vector<RefPtr<ScaledFont>> mScaledFonts; 164 std::unordered_set<SourceSurface*> mStoredSurfaces; 165 std::vector<RefPtr<SourceSurface>> mExternalSurfaces; 166 bool mExternalFonts; 167 }; 168 169 typedef std::function<void(MemStream& aStream, 170 std::vector<RefPtr<ScaledFont>>& aScaledFonts)> 171 SerializeResourcesFn; 172 173 // WARNING: This should not be used in its existing state because 174 // it is likely to OOM because of large continguous allocations. 175 class DrawEventRecorderMemory : public DrawEventRecorderPrivate { 176 public: 177 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderMemory, override) 178 179 /** 180 * Constructs a DrawEventRecorder that stores the recording in memory. 181 */ 182 DrawEventRecorderMemory(); 183 explicit DrawEventRecorderMemory(const SerializeResourcesFn& aSerialize); 184 185 void RecordEvent(const RecordedEvent& aEvent) override; 186 187 void AddDependentSurface(uint64_t aDependencyId) override; 188 189 nsTHashSet<uint64_t>&& TakeDependentSurfaces(); 190 191 /** 192 * @return the current size of the recording (in chars). 193 */ 194 size_t RecordingSize(); 195 196 /** 197 * Wipes the internal recording buffer, but the recorder does NOT forget which 198 * objects it has recorded. This can be used so that a recording can be copied 199 * and processed in chunks, releasing memory as it goes. 200 */ 201 void WipeRecording(); 202 bool Finish() override; 203 void FlushItem(IntRect) override; 204 205 MemStream mOutputStream; 206 /* The index stream is of the form: 207 * ItemIndex { size_t dataEnd; size_t extraDataEnd; } 208 * It gets concatenated to the end of mOutputStream in Finish() 209 * The last size_t in the stream is offset of the begining of the 210 * index. 211 */ 212 MemStream mIndex; 213 214 protected: 215 virtual ~DrawEventRecorderMemory() = default; 216 217 private: 218 SerializeResourcesFn mSerializeCallback; 219 nsTHashSet<uint64_t> mDependentSurfaces; 220 221 void Flush() override; 222 }; 223 224 } // namespace gfx 225 } // namespace mozilla 226 227 #endif /* MOZILLA_GFX_DRAWEVENTRECORDER_H_ */ 228