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 void DrawEventRecorderPrivate::StoreExternalSurfaceRecording(
20 SourceSurface
* aSurface
, uint64_t aKey
) {
21 RecordEvent(RecordedExternalSurfaceCreation(aSurface
, aKey
));
22 mExternalSurfaces
.push_back(aSurface
);
25 void DrawEventRecorderPrivate::StoreSourceSurfaceRecording(
26 SourceSurface
* aSurface
, const char* aReason
) {
27 RefPtr
<DataSourceSurface
> dataSurf
= aSurface
->GetDataSurface();
28 IntSize surfaceSize
= aSurface
->GetSize();
29 Maybe
<DataSourceSurface::ScopedMap
> map
;
31 map
.emplace(dataSurf
, DataSourceSurface::READ
);
33 if (!dataSurf
|| !map
->IsMapped() ||
34 !Factory::AllowedSurfaceSize(surfaceSize
)) {
35 gfxWarning() << "Recording failed to record SourceSurface for " << aReason
;
37 // If surface size is not allowed, replace with reasonable size.
38 if (!Factory::AllowedSurfaceSize(surfaceSize
)) {
39 surfaceSize
.width
= std::min(surfaceSize
.width
, kReasonableSurfaceSize
);
40 surfaceSize
.height
= std::min(surfaceSize
.height
, kReasonableSurfaceSize
);
43 // Insert a dummy source surface.
44 int32_t stride
= surfaceSize
.width
* BytesPerPixel(aSurface
->GetFormat());
45 UniquePtr
<uint8_t[]> sourceData
=
46 MakeUniqueFallible
<uint8_t[]>(stride
* surfaceSize
.height
);
48 // If the surface is too big just create a 1 x 1 dummy.
49 surfaceSize
.width
= 1;
50 surfaceSize
.height
= 1;
51 stride
= surfaceSize
.width
* BytesPerPixel(aSurface
->GetFormat());
52 sourceData
= MakeUnique
<uint8_t[]>(stride
* surfaceSize
.height
);
55 RecordEvent(RecordedSourceSurfaceCreation(aSurface
, sourceData
.get(),
57 aSurface
->GetFormat()));
61 RecordEvent(RecordedSourceSurfaceCreation(
62 aSurface
, map
->GetData(), map
->GetStride(), dataSurf
->GetSize(),
63 dataSurf
->GetFormat()));
66 void DrawEventRecorderPrivate::RecordSourceSurfaceDestruction(void* aSurface
) {
67 RemoveSourceSurface(static_cast<SourceSurface
*>(aSurface
));
68 RemoveStoredObject(aSurface
);
69 RecordEvent(RecordedSourceSurfaceDestruction(ReferencePtr(aSurface
)));
72 void DrawEventRecorderPrivate::DecrementUnscaledFontRefCount(
73 const ReferencePtr aUnscaledFont
) {
74 auto element
= mUnscaledFontRefs
.Lookup(aUnscaledFont
);
75 MOZ_DIAGNOSTIC_ASSERT(element
,
76 "DecrementUnscaledFontRefCount calls should balance "
77 "with IncrementUnscaledFontRefCount calls");
78 if (--element
.Data() <= 0) {
79 RecordEvent(RecordedUnscaledFontDestruction(aUnscaledFont
));
84 void DrawEventRecorderMemory::RecordEvent(const RecordedEvent
& aEvent
) {
85 aEvent
.RecordToStream(mOutputStream
);
88 void DrawEventRecorderMemory::AddDependentSurface(uint64_t aDependencyId
) {
89 mDependentSurfaces
.Insert(aDependencyId
);
92 nsTHashSet
<uint64_t>&& DrawEventRecorderMemory::TakeDependentSurfaces() {
93 return std::move(mDependentSurfaces
);
96 DrawEventRecorderMemory::DrawEventRecorderMemory() {
97 WriteHeader(mOutputStream
);
100 DrawEventRecorderMemory::DrawEventRecorderMemory(
101 const SerializeResourcesFn
& aFn
)
102 : mSerializeCallback(aFn
) {
103 mExternalFonts
= !!mSerializeCallback
;
104 WriteHeader(mOutputStream
);
107 void DrawEventRecorderMemory::Flush() {}
109 void DrawEventRecorderMemory::FlushItem(IntRect aRect
) {
110 MOZ_RELEASE_ASSERT(!aRect
.IsEmpty());
111 // Detaching our existing resources will add some
112 // destruction events to our stream so we need to do that
116 // See moz2d_renderer.rs for a description of the stream format
117 WriteElement(mIndex
, mOutputStream
.mLength
);
119 // write out the fonts into the extra data section
120 mSerializeCallback(mOutputStream
, mScaledFonts
);
121 WriteElement(mIndex
, mOutputStream
.mLength
);
123 WriteElement(mIndex
, aRect
.x
);
124 WriteElement(mIndex
, aRect
.y
);
125 WriteElement(mIndex
, aRect
.XMost());
126 WriteElement(mIndex
, aRect
.YMost());
129 // write out a new header for the next recording in the stream
130 WriteHeader(mOutputStream
);
133 bool DrawEventRecorderMemory::Finish() {
134 // this length might be 0, and things should still work.
135 // for example if there are no items in a particular area
136 size_t indexOffset
= mOutputStream
.mLength
;
137 // write out the index
138 mOutputStream
.write(mIndex
.mData
, mIndex
.mLength
);
139 bool hasItems
= mIndex
.mLength
!= 0;
141 // write out the offset of the Index to the end of the output stream
142 WriteElement(mOutputStream
, indexOffset
);
147 size_t DrawEventRecorderMemory::RecordingSize() {
148 return mOutputStream
.mLength
;
151 void DrawEventRecorderMemory::WipeRecording() {
152 mOutputStream
.reset();
155 WriteHeader(mOutputStream
);
159 } // namespace mozilla