From fabbf757ba1f0fe03a5671eb0bb4936efbb4a890 Mon Sep 17 00:00:00 2001 From: weili Date: Mon, 22 May 2017 12:05:16 -0700 Subject: [PATCH] Add PDF compositor service Currently, the service converts one or multiple pages encapsulated in a SkMultiPictureDocument to a PDF file. It runs in a sandboxed utility process. This allows Chromium to move PDF generation code into a separate process, and eventually can support compositing content generated from multiple processes. BUG=455764 Review-Url: https://codereview.chromium.org/2832633002 Cr-Commit-Position: refs/heads/master@{#473644} --- chrome/app/BUILD.gn | 5 ++ chrome/browser/BUILD.gn | 1 + chrome/browser/browser_resources.grd | 1 + .../browser/chrome_content_browser_client.cc | 17 +++- chrome/utility/BUILD.gn | 7 ++ chrome/utility/DEPS | 2 + .../utility/chrome_content_utility_client.cc | 16 ++++ .../utility/chrome_content_utility_client.h | 1 + components/printing/service/BUILD.gn | 35 ++++++++ components/printing/service/DEPS | 10 +++ components/printing/service/README.md | 4 + .../printing/service/pdf_compositor_impl.cc | 86 +++++++++++++++++++ .../printing/service/pdf_compositor_impl.h | 38 ++++++++ .../service/pdf_compositor_manifest.json | 15 ++++ .../service/pdf_compositor_service.cc | 73 ++++++++++++++++ .../printing/service/pdf_compositor_service.h | 54 ++++++++++++ .../printing/service/public/cpp/BUILD.gn | 35 ++++++++ .../public/cpp/pdf_compositor_client.cc | 58 +++++++++++++ .../public/cpp/pdf_compositor_client.h | 38 ++++++++ .../cpp/pdf_compositor_service_factory.cc | 23 +++++ .../cpp/pdf_compositor_service_factory.h | 20 +++++ .../service/public/interfaces/BUILD.gn | 11 +++ .../printing/service/public/interfaces/OWNERS | 2 + .../public/interfaces/pdf_compositor.mojom | 16 ++++ content/child/child_thread_impl.h | 2 +- .../app/mojo/content_browser_manifest.json | 4 + content/public/child/child_thread.h | 5 +- content/public/renderer/render_thread.h | 1 - content/renderer/render_thread_impl.cc | 10 +-- content/renderer/render_thread_impl.h | 4 +- printing/BUILD.gn | 1 + printing/common/BUILD.gn | 15 ++++ printing/common/pdf_metafile_utils.cc | 46 ++++++++++ printing/common/pdf_metafile_utils.h | 28 ++++++ printing/pdf_metafile_skia.cc | 32 +------ printing/pdf_metafile_skia.h | 7 +- 36 files changed, 674 insertions(+), 49 deletions(-) create mode 100644 components/printing/service/BUILD.gn create mode 100644 components/printing/service/DEPS create mode 100644 components/printing/service/README.md create mode 100644 components/printing/service/pdf_compositor_impl.cc create mode 100644 components/printing/service/pdf_compositor_impl.h create mode 100644 components/printing/service/pdf_compositor_manifest.json create mode 100644 components/printing/service/pdf_compositor_service.cc create mode 100644 components/printing/service/pdf_compositor_service.h create mode 100644 components/printing/service/public/cpp/BUILD.gn create mode 100644 components/printing/service/public/cpp/pdf_compositor_client.cc create mode 100644 components/printing/service/public/cpp/pdf_compositor_client.h create mode 100644 components/printing/service/public/cpp/pdf_compositor_service_factory.cc create mode 100644 components/printing/service/public/cpp/pdf_compositor_service_factory.h create mode 100644 components/printing/service/public/interfaces/BUILD.gn create mode 100644 components/printing/service/public/interfaces/OWNERS create mode 100644 components/printing/service/public/interfaces/pdf_compositor.mojom create mode 100644 printing/common/BUILD.gn create mode 100644 printing/common/pdf_metafile_utils.cc create mode 100644 printing/common/pdf_metafile_utils.h diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn index 2daa56c4818cda..7e40b44e3f22a8 100644 --- a/chrome/app/BUILD.gn +++ b/chrome/app/BUILD.gn @@ -382,6 +382,11 @@ static_library("test_support") { chrome_packaged_services = [ ":chrome_manifest" ] +if (enable_basic_printing || enable_print_preview) { + chrome_packaged_services += + [ "//components/printing/service:pdf_compositor_manifest" ] +} + if (is_chromeos) { chrome_packaged_services += [ "//chrome/browser:preferences_forwarder_manifest" ] diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 7df13cf0f3f58e..c637153b179b52 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn @@ -2581,6 +2581,7 @@ split_static_library("browser") { ] deps += [ "//components/printing/browser", + "//components/printing/service/public/interfaces", "//printing", ] diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 10854ff2726786..77382fa27d8490 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd @@ -143,6 +143,7 @@ + diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 6936ca06824c39..13bf33db8d82fa 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -379,6 +379,10 @@ #include "chrome/browser/media/cast_remoting_connector.h" #endif +#if BUILDFLAG(ENABLE_PRINTING) +#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h" +#endif + #if BUILDFLAG(ENABLE_WAYLAND_SERVER) #include "chrome/browser/chrome_browser_main_extra_parts_exo.h" #endif @@ -3273,9 +3277,13 @@ void ChromeContentBrowserClient::RegisterInProcessServices( void ChromeContentBrowserClient::RegisterOutOfProcessServices( OutOfProcessServiceMap* services) { -#if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS) - services->insert(std::make_pair("media", - base::ASCIIToUTF16("Media Service"))); +#if defined(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS) + services->emplace("media", base::ASCIIToUTF16("Media Service")); +#endif + +#if BUILDFLAG(ENABLE_PRINTING) + services->emplace(printing::mojom::kServiceName, + base::ASCIIToUTF16("PDF Compositor Service")); #endif } @@ -3312,6 +3320,9 @@ ChromeContentBrowserClient::GetExtraServiceManifests() { {nacl::kNaClBrokerServiceName, IDR_NACL_BROKER_MANIFEST}, #endif // defined(OS_WIN) #endif // !defined(DISABLE_NACL) +#if BUILDFLAG(ENABLE_PRINTING) + {printing::mojom::kServiceName, IDR_PDF_COMPOSITOR_MANIFEST}, +#endif }); } diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn index c8482f9eadc2ad..f190c82e37438d 100644 --- a/chrome/utility/BUILD.gn +++ b/chrome/utility/BUILD.gn @@ -175,6 +175,13 @@ static_library("utility") { ] } + if (enable_basic_printing || enable_print_preview) { + deps += [ + "//components/printing/service/public/cpp:factory", + "//components/printing/service/public/interfaces", + ] + } + if (is_mac && safe_browsing_mode == 1) { deps += [ "//chrome/utility/safe_browsing/mac" ] } diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS index 17f0adbaa254dc..32c697ef64c5cc 100644 --- a/chrome/utility/DEPS +++ b/chrome/utility/DEPS @@ -2,6 +2,8 @@ include_rules = [ "+chrome/grit", "+chrome/installer/util", "+components/payments/content/utility", + "+components/printing/service/public/cpp", + "+components/printing/service/public/interfaces", "+components/safe_json", "+components/wifi", "+content/public/child", diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc index 3a028e79c35ef2..763c5d83e49639 100644 --- a/chrome/utility/chrome_content_utility_client.cc +++ b/chrome/utility/chrome_content_utility_client.cc @@ -56,6 +56,12 @@ #include "chrome/utility/printing_handler.h" #endif +#if BUILDFLAG(ENABLE_PRINTING) +#include "chrome/common/chrome_content_client.h" +#include "components/printing/service/public/cpp/pdf_compositor_service_factory.h" +#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h" // nogncheck +#endif + #if defined(FULL_SAFE_BROWSING) #include "chrome/common/safe_archive_analyzer.mojom.h" #include "chrome/common/safe_browsing/zip_analyzer.h" @@ -320,6 +326,16 @@ bool ChromeContentUtilityClient::OnMessageReceived( return false; } +void ChromeContentUtilityClient::RegisterServices( + ChromeContentUtilityClient::StaticServiceMap* services) { +#if BUILDFLAG(ENABLE_PRINTING) + content::ServiceInfo pdf_compositor_info; + pdf_compositor_info.factory = + base::Bind(&printing::CreatePdfCompositorService, GetUserAgent()); + services->emplace(printing::mojom::kServiceName, pdf_compositor_info); +#endif +} + // static void ChromeContentUtilityClient::PreSandboxStartup() { #if BUILDFLAG(ENABLE_EXTENSIONS) diff --git a/chrome/utility/chrome_content_utility_client.h b/chrome/utility/chrome_content_utility_client.h index 31a1ca6656f5d5..70c4b0a554323c 100644 --- a/chrome/utility/chrome_content_utility_client.h +++ b/chrome/utility/chrome_content_utility_client.h @@ -21,6 +21,7 @@ class ChromeContentUtilityClient : public content::ContentUtilityClient { // content::ContentUtilityClient: void UtilityThreadStarted() override; bool OnMessageReceived(const IPC::Message& message) override; + void RegisterServices(StaticServiceMap* services) override; static void PreSandboxStartup(); diff --git a/components/printing/service/BUILD.gn b/components/printing/service/BUILD.gn new file mode 100644 index 00000000000000..077ee2813b0836 --- /dev/null +++ b/components/printing/service/BUILD.gn @@ -0,0 +1,35 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//services/service_manager/public/cpp/service.gni") +import("//services/service_manager/public/service_manifest.gni") + +static_library("service") { + sources = [ + "pdf_compositor_impl.cc", + "pdf_compositor_impl.h", + "pdf_compositor_service.cc", + "pdf_compositor_service.h", + ] + + deps = [ + "//base", + "//components/discardable_memory/client", + "//components/discardable_memory/public/interfaces", + "//content/public/common:service_names", + "//content/public/utility", + "//printing/common", + "//skia", + ] + + public_deps = [ + "//components/printing/service/public/interfaces", + "//services/service_manager/public/cpp", + ] +} + +service_manifest("pdf_compositor_manifest") { + name = "pdf_compositor" + source = "pdf_compositor_manifest.json" +} diff --git a/components/printing/service/DEPS b/components/printing/service/DEPS new file mode 100644 index 00000000000000..839127983cb989 --- /dev/null +++ b/components/printing/service/DEPS @@ -0,0 +1,10 @@ +include_rules = [ + "+components/discardable_memory/client", + "+content/public/common", + "+content/public/utility", + "+mojo/public/cpp", + "+printing/common", + "+services/service_manager/public/cpp", + "+skia", + "+third_party/skia", +] diff --git a/components/printing/service/README.md b/components/printing/service/README.md new file mode 100644 index 00000000000000..6ce9c170a855db --- /dev/null +++ b/components/printing/service/README.md @@ -0,0 +1,4 @@ +The pdf_compositor service should composite multiple raw pictures from different +frames into a complete one, then converts it into a pdf file within an isolated +sandboxed process. Currently, it has no compositing functionality, just convert +a set of raw pictures into a pdf file within the sandboxed process. diff --git a/components/printing/service/pdf_compositor_impl.cc b/components/printing/service/pdf_compositor_impl.cc new file mode 100644 index 00000000000000..c27e466ddd83cd --- /dev/null +++ b/components/printing/service/pdf_compositor_impl.cc @@ -0,0 +1,86 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/printing/service/pdf_compositor_impl.h" + +#include +#include + +#include "base/logging.h" +#include "base/memory/shared_memory.h" +#include "base/memory/shared_memory_handle.h" +#include "mojo/public/cpp/system/platform_handle.h" +#include "printing/common/pdf_metafile_utils.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkDocument.h" +#include "third_party/skia/src/utils/SkMultiPictureDocument.h" + +namespace printing { + +PdfCompositorImpl::PdfCompositorImpl( + const std::string& creator, + std::unique_ptr service_ref) + : service_ref_(std::move(service_ref)), creator_(creator) {} + +PdfCompositorImpl::~PdfCompositorImpl() = default; + +void PdfCompositorImpl::CompositePdf( + mojo::ScopedSharedBufferHandle sk_handle, + mojom::PdfCompositor::CompositePdfCallback callback) { + DCHECK(sk_handle.is_valid()); + + base::SharedMemoryHandle memory_handle; + size_t memory_size = 0; + bool read_only_flag = false; + + const MojoResult result = mojo::UnwrapSharedMemoryHandle( + std::move(sk_handle), &memory_handle, &memory_size, &read_only_flag); + DCHECK_EQ(MOJO_RESULT_OK, result); + DCHECK_GT(memory_size, 0u); + + std::unique_ptr shm = + base::MakeUnique(memory_handle, true); + if (!shm->Map(memory_size)) { + DLOG(ERROR) << "CompositePdf: Shared memory map failed."; + std::move(callback).Run(mojo::ScopedSharedBufferHandle()); + return; + } + + SkMemoryStream stream(shm->memory(), memory_size); + int page_count = SkMultiPictureDocumentReadPageCount(&stream); + if (!page_count) { + DLOG(ERROR) << "CompositePdf: No page is read."; + std::move(callback).Run(mojo::ScopedSharedBufferHandle()); + return; + } + + std::vector pages(page_count); + if (!SkMultiPictureDocumentRead(&stream, pages.data(), page_count)) { + DLOG(ERROR) << "CompositePdf: Page reading failed."; + std::move(callback).Run(mojo::ScopedSharedBufferHandle()); + return; + } + + SkDynamicMemoryWStream wstream; + sk_sp doc = MakePdfDocument(creator_, &wstream); + + for (const auto& page : pages) { + SkCanvas* canvas = doc->beginPage(page.fSize.width(), page.fSize.height()); + canvas->drawPicture(page.fPicture); + doc->endPage(); + } + doc->close(); + + mojo::ScopedSharedBufferHandle buffer = + mojo::SharedBufferHandle::Create(wstream.bytesWritten()); + DCHECK(buffer.is_valid()); + + mojo::ScopedSharedBufferMapping mapping = buffer->Map(wstream.bytesWritten()); + DCHECK(mapping); + wstream.copyToAndReset(mapping.get()); + + std::move(callback).Run(std::move(buffer)); +} + +} // namespace printing diff --git a/components/printing/service/pdf_compositor_impl.h b/components/printing/service/pdf_compositor_impl.h new file mode 100644 index 00000000000000..b7890fa10ee2e7 --- /dev/null +++ b/components/printing/service/pdf_compositor_impl.h @@ -0,0 +1,38 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_IMPL_H_ +#define COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_IMPL_H_ + +#include +#include + +#include "base/macros.h" +#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h" +#include "mojo/public/cpp/system/buffer.h" +#include "services/service_manager/public/cpp/service_context_ref.h" + +namespace printing { + +class PdfCompositorImpl : public mojom::PdfCompositor { + public: + PdfCompositorImpl( + const std::string& creator, + std::unique_ptr service_ref); + ~PdfCompositorImpl() override; + + void CompositePdf( + mojo::ScopedSharedBufferHandle sk_handle, + mojom::PdfCompositor::CompositePdfCallback callback) override; + + private: + const std::unique_ptr service_ref_; + const std::string creator_; + + DISALLOW_COPY_AND_ASSIGN(PdfCompositorImpl); +}; + +} // namespace printing + +#endif // COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_IMPL_H_ diff --git a/components/printing/service/pdf_compositor_manifest.json b/components/printing/service/pdf_compositor_manifest.json new file mode 100644 index 00000000000000..9e9b05929d8852 --- /dev/null +++ b/components/printing/service/pdf_compositor_manifest.json @@ -0,0 +1,15 @@ +{ + "name": "pdf_compositor", + "display_name": "PDF Compositor Service", + "interface_provider_specs": { + "service_manager:connector": { + "provides": { + "composite": [ "printing::mojom::PdfCompositor" ] + }, + "requires": { + "service_manager": [ "service_manager:all_users" ], + "content_browser": [ "utility" ] + } + } + } +} diff --git a/components/printing/service/pdf_compositor_service.cc b/components/printing/service/pdf_compositor_service.cc new file mode 100644 index 00000000000000..d00f3ed76bd658 --- /dev/null +++ b/components/printing/service/pdf_compositor_service.cc @@ -0,0 +1,73 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/printing/service/pdf_compositor_service.h" + +#include + +#include "base/lazy_instance.h" +#include "base/memory/discardable_memory.h" +#include "base/memory/ptr_util.h" +#include "components/printing/service/pdf_compositor_impl.h" +#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h" +#include "content/public/common/service_names.mojom.h" +#include "content/public/utility/utility_thread.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "services/service_manager/public/cpp/connector.h" +#include "services/service_manager/public/cpp/service_context.h" + +namespace { + +void OnPdfCompositorRequest( + const std::string& creator, + service_manager::ServiceContextRefFactory* ref_factory, + const service_manager::BindSourceInfo& source_info, + printing::mojom::PdfCompositorRequest request) { + mojo::MakeStrongBinding(base::MakeUnique( + creator, ref_factory->CreateRef()), + std::move(request)); +} +} // namespace + +namespace printing { + +PdfCompositorService::PdfCompositorService(const std::string& creator) + : creator_(creator.empty() ? "Chromium" : creator), weak_factory_(this) {} + +PdfCompositorService::~PdfCompositorService() = default; + +// static +std::unique_ptr PdfCompositorService::Create( + const std::string& creator) { + return base::MakeUnique(creator); +} + +void PdfCompositorService::OnStart() { + // Set up discardable memory manager. + discardable_memory::mojom::DiscardableSharedMemoryManagerPtr manager_ptr; + context()->connector()->BindInterface(content::mojom::kBrowserServiceName, + &manager_ptr); + discardable_shared_memory_manager_ = base::MakeUnique< + discardable_memory::ClientDiscardableSharedMemoryManager>( + std::move(manager_ptr), content::UtilityThread::Get()->GetIOTaskRunner()); + DCHECK(discardable_shared_memory_manager_); + base::DiscardableMemoryAllocator::SetInstance( + discardable_shared_memory_manager_.get()); + + ref_factory_ = base::MakeUnique( + base::Bind(&service_manager::ServiceContext::RequestQuit, + base::Unretained(context()))); + registry_.AddInterface( + base::Bind(&OnPdfCompositorRequest, creator_, ref_factory_.get())); +} + +void PdfCompositorService::OnBindInterface( + const service_manager::BindSourceInfo& source_info, + const std::string& interface_name, + mojo::ScopedMessagePipeHandle interface_pipe) { + registry_.BindInterface(source_info, interface_name, + std::move(interface_pipe)); +} + +} // namespace printing diff --git a/components/printing/service/pdf_compositor_service.h b/components/printing/service/pdf_compositor_service.h new file mode 100644 index 00000000000000..31672988b5ca84 --- /dev/null +++ b/components/printing/service/pdf_compositor_service.h @@ -0,0 +1,54 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_SERVICE_H_ +#define COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_SERVICE_H_ + +#include +#include + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/discardable_memory/client/client_discardable_shared_memory_manager.h" +#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h" +#include "services/service_manager/public/cpp/bind_source_info.h" +#include "services/service_manager/public/cpp/binder_registry.h" +#include "services/service_manager/public/cpp/service.h" +#include "services/service_manager/public/cpp/service_context_ref.h" + +namespace printing { + +class PdfCompositorService : public service_manager::Service { + public: + explicit PdfCompositorService(const std::string& creator); + ~PdfCompositorService() override; + + // Factory function for use as an embedded service. + static std::unique_ptr Create( + const std::string& creator); + + // service_manager::Service: + void OnStart() override; + void OnBindInterface(const service_manager::BindSourceInfo& source_info, + const std::string& interface_name, + mojo::ScopedMessagePipeHandle interface_pipe) override; + + private: + // The creator of this service. + // Currently contains the service creator's user agent string if given, + // otherwise just use string "Chromium". + const std::string creator_; + + std::unique_ptr + discardable_shared_memory_manager_; + std::unique_ptr ref_factory_; + service_manager::BinderRegistry registry_; + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(PdfCompositorService); +}; + +} // namespace printing + +#endif // COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_SERVICE_H_ diff --git a/components/printing/service/public/cpp/BUILD.gn b/components/printing/service/public/cpp/BUILD.gn new file mode 100644 index 00000000000000..f0c9b84f773352 --- /dev/null +++ b/components/printing/service/public/cpp/BUILD.gn @@ -0,0 +1,35 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +source_set("client") { + sources = [ + "pdf_compositor_client.cc", + "pdf_compositor_client.h", + ] + + public_deps = [ + "//components/printing/service/public/interfaces", + "//services/service_manager/public/cpp", + ] +} + +source_set("factory") { + sources = [ + "pdf_compositor_service_factory.cc", + "pdf_compositor_service_factory.h", + ] + + deps = [ + "//components/printing/service/", + "//content/public/common", + "//content/public/utility", + ] + + public_deps = [ + "//components/printing/service/public/interfaces", + "//services/service_manager/public/cpp", + ] +} diff --git a/components/printing/service/public/cpp/pdf_compositor_client.cc b/components/printing/service/public/cpp/pdf_compositor_client.cc new file mode 100644 index 00000000000000..51aaa560bc6466 --- /dev/null +++ b/components/printing/service/public/cpp/pdf_compositor_client.cc @@ -0,0 +1,58 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/printing/service/public/cpp/pdf_compositor_client.h" + +#include + +#include "mojo/public/cpp/system/platform_handle.h" + +namespace printing { + +namespace { + +// Helper callback which owns an PdfCompositorPtr until invoked. This keeps the +// PdfCompositor pipe open just long enough to dispatch a reply, at which point +// the reply is forwarded to the wrapped |callback|. +void OnCompositePdf( + printing::mojom::PdfCompositorPtr compositor, + printing::mojom::PdfCompositor::CompositePdfCallback callback, + scoped_refptr task_runner, + mojo::ScopedSharedBufferHandle pdf_handle) { + task_runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), + base::Passed(&pdf_handle))); +} + +} // namespace + +PdfCompositorClient::PdfCompositorClient() : compositor_(nullptr) {} + +PdfCompositorClient::~PdfCompositorClient() {} + +void PdfCompositorClient::Connect(service_manager::Connector* connector) { + DCHECK(!compositor_.is_bound()); + connector->BindInterface(mojom::kServiceName, &compositor_); +} + +void PdfCompositorClient::Composite( + service_manager::Connector* connector, + base::SharedMemoryHandle handle, + size_t data_size, + mojom::PdfCompositor::CompositePdfCallback callback, + scoped_refptr callback_task_runner) { + DCHECK(data_size); + + if (!compositor_) + Connect(connector); + + mojo::ScopedSharedBufferHandle buffer_handle = + mojo::WrapSharedMemoryHandle(handle, data_size, true); + + compositor_->CompositePdf( + std::move(buffer_handle), + base::BindOnce(&OnCompositePdf, base::Passed(&compositor_), + std::move(callback), callback_task_runner)); +} + +} // namespace printing diff --git a/components/printing/service/public/cpp/pdf_compositor_client.h b/components/printing/service/public/cpp/pdf_compositor_client.h new file mode 100644 index 00000000000000..d3d8c29b866ae6 --- /dev/null +++ b/components/printing/service/public/cpp/pdf_compositor_client.h @@ -0,0 +1,38 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_COMPOSITOR_CLIENT_H_ +#define COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_COMPOSITOR_CLIENT_H_ + +#include "base/memory/shared_memory_handle.h" +#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h" +#include "services/service_manager/public/cpp/connector.h" + +namespace printing { + +// Helper class to composite a pdf via the pdf_compositor service. +class PdfCompositorClient { + public: + PdfCompositorClient(); + ~PdfCompositorClient(); + + // Composite the final picture and convert into a PDF file. + void Composite(service_manager::Connector* connector, + base::SharedMemoryHandle handle, + size_t data_size, + mojom::PdfCompositor::CompositePdfCallback callback, + scoped_refptr callback_task_runner); + + private: + // Connect to the service. + void Connect(service_manager::Connector* connector); + + mojom::PdfCompositorPtr compositor_; + + DISALLOW_COPY_AND_ASSIGN(PdfCompositorClient); +}; + +} // namespace printing + +#endif // COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_COMPOSITOR_CLIENT_H_ diff --git a/components/printing/service/public/cpp/pdf_compositor_service_factory.cc b/components/printing/service/public/cpp/pdf_compositor_service_factory.cc new file mode 100644 index 00000000000000..f832f86031338b --- /dev/null +++ b/components/printing/service/public/cpp/pdf_compositor_service_factory.cc @@ -0,0 +1,23 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/printing/service/public/cpp/pdf_compositor_service_factory.h" + +#include "components/printing/service/pdf_compositor_service.h" +#include "content/public/utility/utility_thread.h" +#include "third_party/WebKit/public/platform/WebImageGenerator.h" +#include "third_party/skia/include/core/SkGraphics.h" + +namespace printing { + +std::unique_ptr CreatePdfCompositorService( + const std::string& creator) { + content::UtilityThread::Get()->EnsureBlinkInitialized(); + // Hook up blink's codecs so skia can call them. + SkGraphics::SetImageGeneratorFromEncodedDataFactory( + blink::WebImageGenerator::Create); + return printing::PdfCompositorService::Create(creator); +} + +} // namespace printing diff --git a/components/printing/service/public/cpp/pdf_compositor_service_factory.h b/components/printing/service/public/cpp/pdf_compositor_service_factory.h new file mode 100644 index 00000000000000..10d06bab09bd36 --- /dev/null +++ b/components/printing/service/public/cpp/pdf_compositor_service_factory.h @@ -0,0 +1,20 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_COMPOSITOR_SERVICE_FACTORY_H_ +#define COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_COMPOSITOR_SERVICE_FACTORY_H_ + +#include +#include + +#include "services/service_manager/public/cpp/service.h" + +namespace printing { + +std::unique_ptr CreatePdfCompositorService( + const std::string& creator); + +} // namespace printing + +#endif // COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_COMPOSITOR_SERVICE_FACTORY_H_ diff --git a/components/printing/service/public/interfaces/BUILD.gn b/components/printing/service/public/interfaces/BUILD.gn new file mode 100644 index 00000000000000..1efdb19418da26 --- /dev/null +++ b/components/printing/service/public/interfaces/BUILD.gn @@ -0,0 +1,11 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("interfaces") { + sources = [ + "pdf_compositor.mojom", + ] +} diff --git a/components/printing/service/public/interfaces/OWNERS b/components/printing/service/public/interfaces/OWNERS new file mode 100644 index 00000000000000..08850f421205f8 --- /dev/null +++ b/components/printing/service/public/interfaces/OWNERS @@ -0,0 +1,2 @@ +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS diff --git a/components/printing/service/public/interfaces/pdf_compositor.mojom b/components/printing/service/public/interfaces/pdf_compositor.mojom new file mode 100644 index 00000000000000..67f9448d947d27 --- /dev/null +++ b/components/printing/service/public/interfaces/pdf_compositor.mojom @@ -0,0 +1,16 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module printing.mojom; + +const string kServiceName = "pdf_compositor"; + +// TODO(weili): Add support for printing frames from different processes. +interface PdfCompositor { + // Currently directly convert passed in page data to a PDF file. + // |sk_handle| points to a buffer of a Skia MultiPictureDocument. + // |pdf_handle| points to the generated PDF file buffer. + CompositePdf(handle sk_handle) + => (handle pdf_handle); +}; diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h index e9883a2d747c59..a7e2cd2f2565f7 100644 --- a/content/child/child_thread_impl.h +++ b/content/child/child_thread_impl.h @@ -95,6 +95,7 @@ class CONTENT_EXPORT ChildThreadImpl void RecordComputedAction(const std::string& action) override; ServiceManagerConnection* GetServiceManagerConnection() override; service_manager::Connector* GetConnector() override; + scoped_refptr GetIOTaskRunner() override; IPC::SyncChannel* channel() { return channel_.get(); } @@ -192,7 +193,6 @@ class CONTENT_EXPORT ChildThreadImpl void OnChannelError() override; bool IsInBrowserProcess() const; - scoped_refptr GetIOTaskRunner(); private: class ChildThreadMessageRouter : public IPC::MessageRouter { diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json index ea5984ab19bad9..6f051c57653bb6 100644 --- a/content/public/app/mojo/content_browser_manifest.json +++ b/content/public/app/mojo/content_browser_manifest.json @@ -48,6 +48,10 @@ ], "service_manager:service_factory": [ "service_manager::mojom::ServiceFactory" + ], + "utility": [ + "discardable_memory::mojom::DiscardableSharedMemoryManager", + "memory_instrumentation::mojom::Coordinator" ] }, "requires": { diff --git a/content/public/child/child_thread.h b/content/public/child/child_thread.h index 575ee80807c953..950200bd57bdf5 100644 --- a/content/public/child/child_thread.h +++ b/content/public/child/child_thread.h @@ -7,7 +7,7 @@ #include -#include "base/logging.h" +#include "base/memory/ref_counted.h" #include "build/build_config.h" #include "content/common/content_export.h" #include "ipc/ipc_sender.h" @@ -17,6 +17,7 @@ #endif namespace base { +class SingleThreadTaskRunner; struct UserMetricsAction; } @@ -73,6 +74,8 @@ class CONTENT_EXPORT ChildThread : public IPC::Sender { // Returns a connector that can be used to bind interfaces exposed by other // services. virtual service_manager::Connector* GetConnector() = 0; + + virtual scoped_refptr GetIOTaskRunner() = 0; }; } // namespace content diff --git a/content/public/renderer/render_thread.h b/content/public/renderer/render_thread.h index d58570bdbcb41c..d5d1329574ed04 100644 --- a/content/public/renderer/render_thread.h +++ b/content/public/renderer/render_thread.h @@ -53,7 +53,6 @@ class CONTENT_EXPORT RenderThread : virtual public ChildThread { virtual IPC::SyncChannel* GetChannel() = 0; virtual std::string GetLocale() = 0; virtual IPC::SyncMessageFilter* GetSyncMessageFilter() = 0; - virtual scoped_refptr GetIOTaskRunner() = 0; // Called to add or remove a listener for a particular message routing ID. // These methods normally get delegated to a MessageRouter. diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index da073cb259b6df..f191e4f6727fbd 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc @@ -1019,11 +1019,6 @@ IPC::SyncMessageFilter* RenderThreadImpl::GetSyncMessageFilter() { return sync_message_filter(); } -scoped_refptr -RenderThreadImpl::GetIOTaskRunner() { - return ChildProcess::current()->io_task_runner(); -} - void RenderThreadImpl::AddRoute(int32_t routing_id, IPC::Listener* listener) { ChildThreadImpl::GetRouter()->AddRoute(routing_id, listener); auto it = pending_frame_creates_.find(routing_id); @@ -1537,6 +1532,11 @@ void RenderThreadImpl::OnAssociatedInterfaceRequest( ChildThreadImpl::OnAssociatedInterfaceRequest(name, std::move(handle)); } +scoped_refptr +RenderThreadImpl::GetIOTaskRunner() { + return ChildProcess::current()->io_task_runner(); +} + bool RenderThreadImpl::IsGpuRasterizationForced() { return is_gpu_rasterization_forced_; } diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index 0240ef3517495b..deb435fe31016e 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h @@ -193,7 +193,6 @@ class CONTENT_EXPORT RenderThreadImpl IPC::SyncChannel* GetChannel() override; std::string GetLocale() override; IPC::SyncMessageFilter* GetSyncMessageFilter() override; - scoped_refptr GetIOTaskRunner() override; void AddRoute(int32_t routing_id, IPC::Listener* listener) override; void RemoveRoute(int32_t routing_id) override; int GenerateRoutingID() override; @@ -226,6 +225,9 @@ class CONTENT_EXPORT RenderThreadImpl const std::string& name, mojo::ScopedInterfaceEndpointHandle handle) override; + // ChildThread implementation via ChildThreadImpl: + scoped_refptr GetIOTaskRunner() override; + // CompositorDependencies implementation. bool IsGpuRasterizationForced() override; bool IsAsyncWorkerContextEnabled() override; diff --git a/printing/BUILD.gn b/printing/BUILD.gn index 98bc611a231332..eb1fb5abfa740f 100644 --- a/printing/BUILD.gn +++ b/printing/BUILD.gn @@ -95,6 +95,7 @@ component("printing") { "//base:i18n", "//base/third_party/dynamic_annotations", "//cc/paint", + "//printing/common", "//skia", "//third_party/icu", "//ui/gfx", diff --git a/printing/common/BUILD.gn b/printing/common/BUILD.gn new file mode 100644 index 00000000000000..d1b74bb7a43b61 --- /dev/null +++ b/printing/common/BUILD.gn @@ -0,0 +1,15 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("common") { + sources = [ + "pdf_metafile_utils.cc", + "pdf_metafile_utils.h", + ] + + deps = [ + "//base", + "//skia", + ] +} diff --git a/printing/common/pdf_metafile_utils.cc b/printing/common/pdf_metafile_utils.cc new file mode 100644 index 00000000000000..3a30ad0018d6c3 --- /dev/null +++ b/printing/common/pdf_metafile_utils.cc @@ -0,0 +1,46 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "printing/common/pdf_metafile_utils.h" + +#include "base/time/time.h" +#include "third_party/skia/include/core/SkTime.h" + +namespace { + +SkTime::DateTime TimeToSkTime(base::Time time) { + base::Time::Exploded exploded; + time.UTCExplode(&exploded); + SkTime::DateTime skdate; + skdate.fTimeZoneMinutes = 0; + skdate.fYear = exploded.year; + skdate.fMonth = exploded.month; + skdate.fDayOfWeek = exploded.day_of_week; + skdate.fDay = exploded.day_of_month; + skdate.fHour = exploded.hour; + skdate.fMinute = exploded.minute; + skdate.fSecond = exploded.second; + return skdate; +} + +} // namespace + +namespace printing { + +sk_sp MakePdfDocument(const std::string& creator, + SkWStream* stream) { + SkDocument::PDFMetadata metadata; + SkTime::DateTime now = TimeToSkTime(base::Time::Now()); + metadata.fCreation.fEnabled = true; + metadata.fCreation.fDateTime = now; + metadata.fModified.fEnabled = true; + metadata.fModified.fDateTime = now; + metadata.fCreator = creator.empty() + ? SkString("Chromium") + : SkString(creator.c_str(), creator.size()); + return SkDocument::MakePDF(stream, SK_ScalarDefaultRasterDPI, metadata, + nullptr, false); +} + +} // namespace printing diff --git a/printing/common/pdf_metafile_utils.h b/printing/common/pdf_metafile_utils.h new file mode 100644 index 00000000000000..78d2b530f31cbd --- /dev/null +++ b/printing/common/pdf_metafile_utils.h @@ -0,0 +1,28 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PRINTING_COMMON_PDF_METAFILE_UTILS_H_ +#define PRINTING_COMMON_PDF_METAFILE_UTILS_H_ + +#include + +#include "skia/ext/platform_canvas.h" +#include "third_party/skia/include/core/SkDocument.h" +#include "third_party/skia/include/core/SkRefCnt.h" +#include "third_party/skia/include/core/SkStream.h" + +namespace printing { + +enum SkiaDocumentType { + PDF_SKIA_DOCUMENT_TYPE, + // MSKP is an experimental, fragile, and diagnostic-only document type. + MSKP_SKIA_DOCUMENT_TYPE, +}; + +sk_sp MakePdfDocument(const std::string& creator, + SkWStream* stream); + +} // namespace printing + +#endif // PRINTING_COMMON_PDF_METAFILE_UTILS_H_ diff --git a/printing/pdf_metafile_skia.cc b/printing/pdf_metafile_skia.cc index 4e154845a55aaa..2e3b07b2c3c6b7 100644 --- a/printing/pdf_metafile_skia.cc +++ b/printing/pdf_metafile_skia.cc @@ -16,7 +16,6 @@ #include "cc/paint/paint_recorder.h" #include "cc/paint/skia_paint_canvas.h" #include "printing/print_settings.h" -#include "third_party/skia/include/core/SkDocument.h" #include "third_party/skia/include/core/SkStream.h" // Note that headers in third_party/skia/src are fragile. This is // an experimental, fragile, and diagnostic-only document type. @@ -45,35 +44,6 @@ bool WriteAssetToBuffer(const SkStreamAsset* asset, return (length == assetCopy->read(buffer, length)); } -SkTime::DateTime TimeToSkTime(base::Time time) { - base::Time::Exploded exploded; - time.UTCExplode(&exploded); - SkTime::DateTime skdate; - skdate.fTimeZoneMinutes = 0; - skdate.fYear = exploded.year; - skdate.fMonth = exploded.month; - skdate.fDayOfWeek = exploded.day_of_week; - skdate.fDay = exploded.day_of_month; - skdate.fHour = exploded.hour; - skdate.fMinute = exploded.minute; - skdate.fSecond = exploded.second; - return skdate; -} - -sk_sp MakePdfDocument(SkWStream* wStream) { - SkDocument::PDFMetadata metadata; - SkTime::DateTime now = TimeToSkTime(base::Time::Now()); - metadata.fCreation.fEnabled = true; - metadata.fCreation.fDateTime = now; - metadata.fModified.fEnabled = true; - metadata.fModified.fDateTime = now; - const std::string& agent = printing::GetAgent(); - metadata.fCreator = agent.empty() ? SkString("Chromium") - : SkString(agent.c_str(), agent.size()); - return SkDocument::MakePDF(wStream, SK_ScalarDefaultRasterDPI, metadata, - nullptr, false); -} - } // namespace namespace printing { @@ -192,7 +162,7 @@ bool PdfMetafileSkia::FinishDocument() { sk_sp doc; switch (data_->type_) { case PDF_SKIA_DOCUMENT_TYPE: - doc = MakePdfDocument(&stream); + doc = MakePdfDocument(printing::GetAgent(), &stream); break; case MSKP_SKIA_DOCUMENT_TYPE: doc = SkMakeMultiPictureDocument(&stream); diff --git a/printing/pdf_metafile_skia.h b/printing/pdf_metafile_skia.h index 948e27f45e088f..dacd1a74cb0a2b 100644 --- a/printing/pdf_metafile_skia.h +++ b/printing/pdf_metafile_skia.h @@ -12,6 +12,7 @@ #include "base/macros.h" #include "build/build_config.h" #include "cc/paint/paint_canvas.h" +#include "printing/common/pdf_metafile_utils.h" #include "printing/metafile.h" #include "skia/ext/platform_canvas.h" @@ -21,12 +22,6 @@ namespace printing { -enum SkiaDocumentType { - PDF_SKIA_DOCUMENT_TYPE, - // MSKP is an experimental, fragile, and diagnostic-only document type. - MSKP_SKIA_DOCUMENT_TYPE, -}; - struct PdfMetafileSkiaData; // This class uses Skia graphics library to generate a PDF document.