tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DrawEventRecorder.h (4892B)


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