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/. */
7 #include "DrawEventRecorder.h"
9 #include "mozilla/UniquePtrExtensions.h"
10 #include "PathRecording.h"
11 #include "RecordingTypes.h"
12 #include "RecordedEventImpl.h"
17 DrawEventRecorderPrivate::DrawEventRecorderPrivate() : mExternalFonts(false) {}
19 DrawEventRecorderPrivate::~DrawEventRecorderPrivate() = default;
21 void DrawEventRecorderPrivate::SetDrawTarget(ReferencePtr aDT
) {
22 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
24 RecordEvent(RecordedSetCurrentDrawTarget(aDT
));
28 void DrawEventRecorderPrivate::StoreExternalSurfaceRecording(
29 SourceSurface
* aSurface
, uint64_t aKey
) {
30 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
32 RecordEvent(RecordedExternalSurfaceCreation(aSurface
, aKey
));
33 mExternalSurfaces
.push_back({aSurface
});
36 void DrawEventRecorderPrivate::StoreSourceSurfaceRecording(
37 SourceSurface
* aSurface
, const char* aReason
) {
38 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
40 RefPtr
<DataSourceSurface
> dataSurf
= aSurface
->GetDataSurface();
41 IntSize surfaceSize
= aSurface
->GetSize();
42 Maybe
<DataSourceSurface::ScopedMap
> map
;
44 map
.emplace(dataSurf
, DataSourceSurface::READ
);
46 if (!dataSurf
|| !map
->IsMapped() ||
47 !Factory::AllowedSurfaceSize(surfaceSize
)) {
48 gfxWarning() << "Recording failed to record SourceSurface for " << aReason
;
50 // If surface size is not allowed, replace with reasonable size.
51 if (!Factory::AllowedSurfaceSize(surfaceSize
)) {
52 surfaceSize
.width
= std::min(surfaceSize
.width
, kReasonableSurfaceSize
);
53 surfaceSize
.height
= std::min(surfaceSize
.height
, kReasonableSurfaceSize
);
56 // Insert a dummy source surface.
57 int32_t stride
= surfaceSize
.width
* BytesPerPixel(aSurface
->GetFormat());
58 UniquePtr
<uint8_t[]> sourceData
=
59 MakeUniqueFallible
<uint8_t[]>(stride
* surfaceSize
.height
);
61 // If the surface is too big just create a 1 x 1 dummy.
62 surfaceSize
.width
= 1;
63 surfaceSize
.height
= 1;
64 stride
= surfaceSize
.width
* BytesPerPixel(aSurface
->GetFormat());
65 sourceData
= MakeUnique
<uint8_t[]>(stride
* surfaceSize
.height
);
68 RecordEvent(RecordedSourceSurfaceCreation(aSurface
, sourceData
.get(),
70 aSurface
->GetFormat()));
74 RecordEvent(RecordedSourceSurfaceCreation(
75 aSurface
, map
->GetData(), map
->GetStride(), dataSurf
->GetSize(),
76 dataSurf
->GetFormat()));
79 void DrawEventRecorderPrivate::RecordSourceSurfaceDestruction(void* aSurface
) {
80 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
82 RemoveSourceSurface(static_cast<SourceSurface
*>(aSurface
));
83 RemoveStoredObject(aSurface
);
84 RecordEvent(RecordedSourceSurfaceDestruction(ReferencePtr(aSurface
)));
87 void DrawEventRecorderPrivate::DecrementUnscaledFontRefCount(
88 const ReferencePtr aUnscaledFont
) {
89 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
91 auto element
= mUnscaledFontRefs
.Lookup(aUnscaledFont
);
92 MOZ_DIAGNOSTIC_ASSERT(element
,
93 "DecrementUnscaledFontRefCount calls should balance "
94 "with IncrementUnscaledFontRefCount calls");
95 if (--element
.Data() <= 0) {
96 RecordEvent(RecordedUnscaledFontDestruction(aUnscaledFont
));
101 void DrawEventRecorderMemory::RecordEvent(const RecordedEvent
& aEvent
) {
102 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderMemory
);
103 aEvent
.RecordToStream(mOutputStream
);
106 void DrawEventRecorderMemory::AddDependentSurface(uint64_t aDependencyId
) {
107 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderMemory
);
108 mDependentSurfaces
.Insert(aDependencyId
);
111 nsTHashSet
<uint64_t>&& DrawEventRecorderMemory::TakeDependentSurfaces() {
112 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderMemory
);
113 return std::move(mDependentSurfaces
);
116 DrawEventRecorderMemory::DrawEventRecorderMemory() {
117 WriteHeader(mOutputStream
);
120 DrawEventRecorderMemory::DrawEventRecorderMemory(
121 const SerializeResourcesFn
& aFn
)
122 : mSerializeCallback(aFn
) {
123 mExternalFonts
= !!mSerializeCallback
;
124 WriteHeader(mOutputStream
);
127 void DrawEventRecorderMemory::Flush() {
128 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderMemory
);
131 void DrawEventRecorderMemory::FlushItem(IntRect aRect
) {
132 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderMemory
);
134 MOZ_RELEASE_ASSERT(!aRect
.IsEmpty());
135 // Detaching our existing resources will add some
136 // destruction events to our stream so we need to do that
140 // See moz2d_renderer.rs for a description of the stream format
141 WriteElement(mIndex
, mOutputStream
.mLength
);
143 // write out the fonts into the extra data section
144 mSerializeCallback(mOutputStream
, mScaledFonts
);
145 WriteElement(mIndex
, mOutputStream
.mLength
);
147 WriteElement(mIndex
, aRect
.x
);
148 WriteElement(mIndex
, aRect
.y
);
149 WriteElement(mIndex
, aRect
.XMost());
150 WriteElement(mIndex
, aRect
.YMost());
153 // write out a new header for the next recording in the stream
154 WriteHeader(mOutputStream
);
157 bool DrawEventRecorderMemory::Finish() {
158 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderMemory
);
160 // this length might be 0, and things should still work.
161 // for example if there are no items in a particular area
162 size_t indexOffset
= mOutputStream
.mLength
;
163 // write out the index
164 mOutputStream
.write(mIndex
.mData
, mIndex
.mLength
);
165 bool hasItems
= mIndex
.mLength
!= 0;
167 // write out the offset of the Index to the end of the output stream
168 WriteElement(mOutputStream
, indexOffset
);
173 size_t DrawEventRecorderMemory::RecordingSize() {
174 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderMemory
);
175 return mOutputStream
.mLength
;
178 void DrawEventRecorderMemory::WipeRecording() {
179 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderMemory
);
181 mOutputStream
.reset();
184 WriteHeader(mOutputStream
);
188 } // namespace mozilla