1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
/* -*- 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_layout_printing_DrawEventRecorder_h
#define mozilla_layout_printing_DrawEventRecorder_h
#include <memory>
#include "mozilla/gfx/DrawEventRecorder.h"
#include "mozilla/gfx/RecordingTypes.h"
#include "prio.h"
#include "nsTArray.h"
namespace mozilla {
namespace layout {
class PRFileDescStream final : public mozilla::gfx::EventStream {
// Most writes, as seen in the print IPC use case, are very small (<32 bytes),
// with a small number of very large (>40KB) writes. Writes larger than this
// value are not buffered.
static const size_t kBufferSize = 1024;
public:
PRFileDescStream()
: mFd(nullptr), mBuffer(nullptr), mBufferPos(0), mGood(true) {}
PRFileDescStream(const PRFileDescStream& other) = delete;
~PRFileDescStream() { Close(); }
void OpenFD(PRFileDesc* aFd) {
MOZ_DIAGNOSTIC_ASSERT(!IsOpen());
mFd = aFd;
mGood = !!mFd;
mBuffer.reset(new uint8_t[kBufferSize]);
mBufferPos = 0;
}
void Close() {
// We need to be API compatible with std::ostream, and so we silently handle
// closes on a closed FD.
if (IsOpen()) {
Flush();
PR_Close(mFd);
mFd = nullptr;
mBuffer.reset();
mBufferPos = 0;
}
}
bool IsOpen() { return mFd != nullptr; }
void Flush() {
// See comment in Close().
if (IsOpen() && mBufferPos > 0) {
PRInt32 length =
PR_Write(mFd, static_cast<const void*>(mBuffer.get()), mBufferPos);
mGood = length >= 0 && static_cast<size_t>(length) == mBufferPos;
mBufferPos = 0;
}
}
void Seek(PRInt64 aOffset, PRSeekWhence aWhence) {
Flush();
PRInt64 pos = PR_Seek64(mFd, aOffset, aWhence);
mGood = pos != -1;
}
void write(const char* aData, size_t aSize) override {
if (!good()) {
return;
}
// See comment in Close().
if (IsOpen()) {
// If we're writing more data than could ever fit in our buffer, flush the
// buffer and write directly.
if (aSize > kBufferSize) {
Flush();
PRInt32 length = PR_Write(mFd, static_cast<const void*>(aData), aSize);
mGood = length >= 0 && static_cast<size_t>(length) == aSize;
// If our write could fit in our buffer, but doesn't because the buffer
// is partially full, write to the buffer, flush the buffer, and then
// write the rest of the data to the buffer.
} else if (aSize > AvailableBufferSpace()) {
size_t length = AvailableBufferSpace();
WriteToBuffer(aData, length);
Flush();
WriteToBuffer(aData + length, aSize - length);
// Write fits in the buffer.
} else {
WriteToBuffer(aData, aSize);
}
}
}
void read(char* aOut, size_t aSize) override {
if (!good()) {
return;
}
Flush();
PRInt32 res = PR_Read(mFd, static_cast<void*>(aOut), aSize);
mGood = res >= 0 && (static_cast<size_t>(res) == aSize);
}
bool good() final { return mGood; }
void SetIsBad() final { mGood = false; }
private:
size_t AvailableBufferSpace() { return kBufferSize - mBufferPos; }
void WriteToBuffer(const char* aData, size_t aSize) {
MOZ_ASSERT(aSize <= AvailableBufferSpace());
memcpy(mBuffer.get() + mBufferPos, aData, aSize);
mBufferPos += aSize;
}
PRFileDesc* mFd;
std::unique_ptr<uint8_t[]> mBuffer;
size_t mBufferPos;
bool mGood;
};
class DrawEventRecorderPRFileDesc final : public gfx::DrawEventRecorderPrivate {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPRFileDesc, override)
explicit DrawEventRecorderPRFileDesc() = default;
~DrawEventRecorderPRFileDesc();
gfx::RecorderType GetRecorderType() const final {
return gfx::RecorderType::PRFILEDESC;
}
void RecordEvent(const gfx::RecordedEvent& aEvent) override;
/**
* Returns whether a recording file is currently open.
*/
bool IsOpen();
/**
* Opens the recorder with the provided PRFileDesc *.
*/
void OpenFD(PRFileDesc* aFd);
/**
* Closes the file so that it can be processed. The recorder does NOT forget
* which objects it has recorded. This can be used with OpenNew, so that a
* recording can be processed in chunks. The file must be open.
*/
void Close();
void AddDependentSurface(uint64_t aDependencyId) override;
nsTArray<uint64_t>&& TakeDependentSurfaces();
private:
void Flush() override;
PRFileDescStream mOutputStream;
nsTArray<uint64_t> mDependentSurfaces;
};
} // namespace layout
} // namespace mozilla
#endif /* mozilla_layout_printing_DrawEventRecorder_h */
|