tor-browser

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

PrintTargetSkPDF.cpp (4966B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "PrintTargetSkPDF.h"
      7 
      8 #include "include/core/SkStream.h"
      9 #include "mozilla/gfx/2D.h"
     10 #include "nsString.h"
     11 
     12 #include "skia/src/pdf/SkPDFUtils.h"
     13 
     14 namespace mozilla::gfx {
     15 
     16 PrintTargetSkPDF::PrintTargetSkPDF(const IntSize& aSize,
     17                                   UniquePtr<SkWStream> aStream)
     18    : PrintTarget(/* not using cairo_surface_t */ nullptr, aSize),
     19      mOStream(std::move(aStream)),
     20      mPageCanvas(nullptr),
     21      mRefCanvas(nullptr) {}
     22 
     23 PrintTargetSkPDF::~PrintTargetSkPDF() {
     24  Finish();  // ensure stream is flushed
     25 
     26  // Make sure mPDFDoc and mRefPDFDoc are destroyed before our member streams
     27  // (which they wrap) are destroyed:
     28  mPDFDoc = nullptr;
     29  mRefPDFDoc = nullptr;
     30 }
     31 
     32 /* static */
     33 already_AddRefed<PrintTargetSkPDF> PrintTargetSkPDF::CreateOrNull(
     34    UniquePtr<SkWStream> aStream, const IntSize& aSizeInPoints) {
     35  return do_AddRef(new PrintTargetSkPDF(aSizeInPoints, std::move(aStream)));
     36 }
     37 
     38 class GkSkWStream final : public SkWStream {
     39 public:
     40  explicit GkSkWStream(nsIOutputStream* aStream) : mStream(aStream) {
     41    MOZ_ASSERT(mStream);
     42  }
     43  bool write(const void* aBuf, size_t aSize) override {
     44    const auto* data = reinterpret_cast<const char*>(aBuf);
     45    do {
     46      uint32_t wrote = 0;
     47      if (NS_WARN_IF(NS_FAILED(mStream->Write(data, aSize, &wrote)))) {
     48        return false;
     49      }
     50      mWritten += wrote;
     51      data += wrote;
     52      aSize -= wrote;
     53    } while (aSize);
     54    NS_ASSERTION(aSize == 0, "not everything was written to the file");
     55    return true;
     56  }
     57  void flush() override { (void)NS_WARN_IF(NS_FAILED(mStream->Flush())); }
     58  size_t bytesWritten() const override { return mWritten; }
     59 
     60 private:
     61  nsCOMPtr<nsIOutputStream> mStream;
     62  size_t mWritten = 0;
     63 };
     64 
     65 already_AddRefed<PrintTargetSkPDF> PrintTargetSkPDF::CreateOrNull(
     66    nsIOutputStream* aStream, const IntSize& aSizeInPoints) {
     67  return CreateOrNull(MakeUnique<GkSkWStream>(aStream), aSizeInPoints);
     68 }
     69 
     70 nsresult PrintTargetSkPDF::BeginPrinting(const nsAString& aTitle,
     71                                         const nsAString& aPrintToFileName,
     72                                         int32_t aStartPage, int32_t aEndPage) {
     73  // We need to create the SkPDFDocument here rather than in CreateOrNull
     74  // because it's only now that we are given aTitle which we want for the
     75  // PDF metadata.
     76 
     77  NS_ConvertUTF16toUTF8 title(aTitle);
     78  SkPDF::Metadata metadata;
     79  metadata.fTitle = SkString(title.get(), title.Length());
     80  metadata.fCreator = "Firefox";
     81  SkPDF::DateTime now = {0};
     82  SkPDFUtils::GetDateTime(&now);
     83  metadata.fCreation = now;
     84  metadata.fModified = now;
     85 
     86  // TODO(emilio, bug 2001912): Provide jpeg decoder / encoders for SkPdf?
     87  metadata.allowNoJpegs = true;
     88 
     89  // SkDocument stores a non-owning raw pointer to aStream
     90  mPDFDoc = SkPDF::MakeDocument(mOStream.get(), metadata);
     91 
     92  return mPDFDoc ? NS_OK : NS_ERROR_FAILURE;
     93 }
     94 
     95 nsresult PrintTargetSkPDF::BeginPage(const IntSize& aSizeInPoints) {
     96  mPageCanvas = mPDFDoc->beginPage(mSize.width, mSize.height);
     97 
     98  return !mPageCanvas ? NS_ERROR_FAILURE
     99                      : PrintTarget::BeginPage(aSizeInPoints);
    100 }
    101 
    102 nsresult PrintTargetSkPDF::EndPage() {
    103  mPageCanvas = nullptr;
    104  mPageDT = nullptr;
    105  return PrintTarget::EndPage();
    106 }
    107 
    108 nsresult PrintTargetSkPDF::EndPrinting() {
    109  mPDFDoc->close();
    110  if (mRefPDFDoc) {
    111    mRefPDFDoc->close();
    112  }
    113  mPageCanvas = nullptr;
    114  mPageDT = nullptr;
    115  return NS_OK;
    116 }
    117 
    118 void PrintTargetSkPDF::Finish() {
    119  if (mIsFinished) {
    120    return;
    121  }
    122  mOStream->flush();
    123  PrintTarget::Finish();
    124 }
    125 
    126 already_AddRefed<DrawTarget> PrintTargetSkPDF::MakeDrawTarget(
    127    const IntSize& aSize, DrawEventRecorder* aRecorder) {
    128  if (aRecorder) {
    129    return PrintTarget::MakeDrawTarget(aSize, aRecorder);
    130  }
    131  // MOZ_ASSERT(aSize == mSize, "Should mPageCanvas size match?");
    132  if (!mPageCanvas) {
    133    return nullptr;
    134  }
    135  mPageDT = Factory::CreateDrawTargetWithSkCanvas(mPageCanvas);
    136  if (!mPageDT) {
    137    mPageCanvas = nullptr;
    138    return nullptr;
    139  }
    140  return do_AddRef(mPageDT);
    141 }
    142 
    143 already_AddRefed<DrawTarget> PrintTargetSkPDF::GetReferenceDrawTarget() {
    144  if (!mRefDT) {
    145    SkPDF::Metadata metadata;
    146    metadata.allowNoJpegs = true;
    147    // SkDocument stores a non-owning raw pointer to aStream
    148    mRefPDFDoc = SkPDF::MakeDocument(&mRefOStream, metadata);
    149    if (!mRefPDFDoc) {
    150      return nullptr;
    151    }
    152    mRefCanvas = mRefPDFDoc->beginPage(mSize.width, mSize.height);
    153    if (!mRefCanvas) {
    154      return nullptr;
    155    }
    156    RefPtr<DrawTarget> dt = Factory::CreateDrawTargetWithSkCanvas(mRefCanvas);
    157    if (!dt) {
    158      return nullptr;
    159    }
    160    mRefDT = std::move(dt);
    161  }
    162 
    163  return do_AddRef(mRefDT);
    164 }
    165 
    166 }  // namespace mozilla::gfx