tor-browser

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

commit d5cc33ca42b4ea666d4ea66079a85f9ecb61b23e
parent 8d67b86f7e0e664c4a3f1a8463c75b3e52689373
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date:   Mon, 24 Nov 2025 11:51:03 +0000

Bug 2001909 - Add a default-off pref to force print-to-pdf to go via SkPdf. r=jfkthame

This allows basic print to PDF using SkPdf.

The jpeg decoder bit seems optional (as in, images and so work without it), but
probably recommended and something that should be fixed before enabling by
default. Filed bug 2001912 for that.

Differential Revision: https://phabricator.services.mozilla.com/D273751

Diffstat:
Mgfx/thebes/PrintTargetPDF.cpp | 11++++++++++-
Mgfx/thebes/PrintTargetPDF.h | 3++-
Mgfx/thebes/PrintTargetSkPDF.cpp | 40+++++++++++++++++++++++++++++++++++++++-
Mgfx/thebes/PrintTargetSkPDF.h | 5++---
Mmodules/libpref/init/StaticPrefList.yaml | 8++++++++
Mwidget/cocoa/nsDeviceContextSpecX.mm | 4+---
6 files changed, 62 insertions(+), 9 deletions(-)

diff --git a/gfx/thebes/PrintTargetPDF.cpp b/gfx/thebes/PrintTargetPDF.cpp @@ -4,6 +4,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "PrintTargetPDF.h" +#ifdef MOZ_ENABLE_SKIA_PDF +# include "PrintTargetSkPDF.h" +#endif #include "cairo.h" #include "cairo-pdf.h" @@ -48,12 +51,18 @@ PrintTargetPDF::~PrintTargetPDF() { } /* static */ -already_AddRefed<PrintTargetPDF> PrintTargetPDF::CreateOrNull( +already_AddRefed<PrintTarget> PrintTargetPDF::CreateOrNull( nsIOutputStream* aStream, const IntSize& aSizeInPoints) { if (NS_WARN_IF(!aStream)) { return nullptr; } +#ifdef MOZ_ENABLE_SKIA_PDF + if (StaticPrefs::print_experimental_skpdf()) { + return PrintTargetSkPDF::CreateOrNull(aStream, aSizeInPoints); + } +#endif + cairo_surface_t* surface = cairo_pdf_surface_create_for_stream( write_func, (void*)aStream, aSizeInPoints.width, aSizeInPoints.height); if (cairo_surface_status(surface)) { diff --git a/gfx/thebes/PrintTargetPDF.h b/gfx/thebes/PrintTargetPDF.h @@ -18,7 +18,8 @@ namespace gfx { */ class PrintTargetPDF final : public PrintTarget { public: - static already_AddRefed<PrintTargetPDF> CreateOrNull( + // NOTE: Might create a PrintTargetSkPDF. + static already_AddRefed<PrintTarget> CreateOrNull( nsIOutputStream* aStream, const IntSize& aSizeInPoints); nsresult BeginPage(const IntSize& aSizeInPoints) override; diff --git a/gfx/thebes/PrintTargetSkPDF.cpp b/gfx/thebes/PrintTargetSkPDF.cpp @@ -5,6 +5,7 @@ #include "PrintTargetSkPDF.h" +#include "include/core/SkStream.h" #include "mozilla/gfx/2D.h" #include "nsString.h" @@ -34,6 +35,38 @@ already_AddRefed<PrintTargetSkPDF> PrintTargetSkPDF::CreateOrNull( return do_AddRef(new PrintTargetSkPDF(aSizeInPoints, std::move(aStream))); } +class GkSkWStream final : public SkWStream { + public: + explicit GkSkWStream(nsIOutputStream* aStream) : mStream(aStream) { + MOZ_ASSERT(mStream); + } + bool write(const void* aBuf, size_t aSize) override { + const auto* data = reinterpret_cast<const char*>(aBuf); + do { + uint32_t wrote = 0; + if (NS_WARN_IF(NS_FAILED(mStream->Write(data, aSize, &wrote)))) { + return false; + } + mWritten += wrote; + data += wrote; + aSize -= wrote; + } while (aSize); + NS_ASSERTION(aSize == 0, "not everything was written to the file"); + return true; + } + void flush() override { (void)NS_WARN_IF(NS_FAILED(mStream->Flush())); } + size_t bytesWritten() const override { return mWritten; } + + private: + nsCOMPtr<nsIOutputStream> mStream; + size_t mWritten = 0; +}; + +already_AddRefed<PrintTargetSkPDF> PrintTargetSkPDF::CreateOrNull( + nsIOutputStream* aStream, const IntSize& aSizeInPoints) { + return CreateOrNull(MakeUnique<GkSkWStream>(aStream), aSizeInPoints); +} + nsresult PrintTargetSkPDF::BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName, int32_t aStartPage, int32_t aEndPage) { @@ -41,14 +74,18 @@ nsresult PrintTargetSkPDF::BeginPrinting(const nsAString& aTitle, // because it's only now that we are given aTitle which we want for the // PDF metadata. + NS_ConvertUTF16toUTF8 title(aTitle); SkPDF::Metadata metadata; - metadata.fTitle = NS_ConvertUTF16toUTF8(aTitle).get(); + metadata.fTitle = SkString(title.get(), title.Length()); metadata.fCreator = "Firefox"; SkPDF::DateTime now = {0}; SkPDFUtils::GetDateTime(&now); metadata.fCreation = now; metadata.fModified = now; + // TODO(emilio, bug 2001912): Provide jpeg decoder / encoders for SkPdf? + metadata.allowNoJpegs = true; + // SkDocument stores a non-owning raw pointer to aStream mPDFDoc = SkPDF::MakeDocument(mOStream.get(), metadata); @@ -106,6 +143,7 @@ already_AddRefed<DrawTarget> PrintTargetSkPDF::MakeDrawTarget( already_AddRefed<DrawTarget> PrintTargetSkPDF::GetReferenceDrawTarget() { if (!mRefDT) { SkPDF::Metadata metadata; + metadata.allowNoJpegs = true; // SkDocument stores a non-owning raw pointer to aStream mRefPDFDoc = SkPDF::MakeDocument(&mRefOStream, metadata); if (!mRefPDFDoc) { diff --git a/gfx/thebes/PrintTargetSkPDF.h b/gfx/thebes/PrintTargetSkPDF.h @@ -21,11 +21,10 @@ namespace gfx { */ class PrintTargetSkPDF final : public PrintTarget { public: - // The returned PrintTargetSkPDF keeps a raw pointer to the passed SkWStream - // but does not own it. Callers are responsible for ensuring that passed - // stream outlives the returned PrintTarget. static already_AddRefed<PrintTargetSkPDF> CreateOrNull( UniquePtr<SkWStream> aStream, const IntSize& aSizeInPoints); + static already_AddRefed<PrintTargetSkPDF> CreateOrNull( + nsIOutputStream* aStream, const IntSize& aSizeInPoints); nsresult BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName, int32_t aStartPage, diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml @@ -16204,6 +16204,14 @@ value: 2 mirror: always +#ifdef MOZ_ENABLE_SKIA_PDF +# Whether we should try to use skpdf for pdf output. +- name: print.experimental.skpdf + type: RelaxedAtomicBool + value: false + mirror: always +#endif + #--------------------------------------------------------------------------- # Prefs starting with "privacy." #--------------------------------------------------------------------------- diff --git a/widget/cocoa/nsDeviceContextSpecX.mm b/widget/cocoa/nsDeviceContextSpecX.mm @@ -99,9 +99,7 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, [printInfo release]; #ifdef MOZ_ENABLE_SKIA_PDF - nsAutoString printViaPdf; - mozilla::Preferences::GetString("print.print_via_pdf_encoder", printViaPdf); - if (printViaPdf.EqualsLiteral("skia-pdf")) { + if (StaticPrefs::print_experimental_skpdf()) { // Annoyingly, PMPrinterPrintWithFile does not pay attention to the // kPMDestination* value set in the PMPrintSession; it always sends the PDF // to the specified printer. This means that if we create the PDF using