Skip to content

Commit

Permalink
Add PDF compositor service
Browse files Browse the repository at this point in the history
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}
  • Loading branch information
weili0 authored and Commit bot committed May 22, 2017
1 parent 222e5e8 commit fabbf75
Show file tree
Hide file tree
Showing 36 changed files with 674 additions and 49 deletions.
5 changes: 5 additions & 0 deletions chrome/app/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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" ]
Expand Down
1 change: 1 addition & 0 deletions chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -2581,6 +2581,7 @@ split_static_library("browser") {
]
deps += [
"//components/printing/browser",
"//components/printing/service/public/interfaces",
"//printing",
]

Expand Down
1 change: 1 addition & 0 deletions chrome/browser/browser_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
</if>
<if expr="enable_printing">
<include name="IDR_CLOUDPRINT_MANIFEST" file="resources\cloud_print_app\manifest.json" type="BINDATA" />
<include name="IDR_PDF_COMPOSITOR_MANIFEST" file="..\..\components\printing\service\pdf_compositor_manifest.json" type="BINDATA" />
</if>
<if expr="not is_ios">
<include name="IDR_DEVTOOLS_DISCOVERY_PAGE_HTML" file="devtools\frontend\devtools_discovery_page.html" type="BINDATA"/>
Expand Down
17 changes: 14 additions & 3 deletions chrome/browser/chrome_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
});
}

Expand Down
7 changes: 7 additions & 0 deletions chrome/utility/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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" ]
}
Expand Down
2 changes: 2 additions & 0 deletions chrome/utility/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
16 changes: 16 additions & 0 deletions chrome/utility/chrome_content_utility_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions chrome/utility/chrome_content_utility_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
35 changes: 35 additions & 0 deletions components/printing/service/BUILD.gn
Original file line number Diff line number Diff line change
@@ -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"
}
10 changes: 10 additions & 0 deletions components/printing/service/DEPS
Original file line number Diff line number Diff line change
@@ -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",
]
4 changes: 4 additions & 0 deletions components/printing/service/README.md
Original file line number Diff line number Diff line change
@@ -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.
86 changes: 86 additions & 0 deletions components/printing/service/pdf_compositor_impl.cc
Original file line number Diff line number Diff line change
@@ -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 <utility>
#include <vector>

#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_manager::ServiceContextRef> 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<base::SharedMemory> shm =
base::MakeUnique<base::SharedMemory>(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<SkDocumentPage> 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<SkDocument> 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
38 changes: 38 additions & 0 deletions components/printing/service/pdf_compositor_impl.h
Original file line number Diff line number Diff line change
@@ -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 <memory>
#include <string>

#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_manager::ServiceContextRef> service_ref);
~PdfCompositorImpl() override;

void CompositePdf(
mojo::ScopedSharedBufferHandle sk_handle,
mojom::PdfCompositor::CompositePdfCallback callback) override;

private:
const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
const std::string creator_;

DISALLOW_COPY_AND_ASSIGN(PdfCompositorImpl);
};

} // namespace printing

#endif // COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_IMPL_H_
15 changes: 15 additions & 0 deletions components/printing/service/pdf_compositor_manifest.json
Original file line number Diff line number Diff line change
@@ -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" ]
}
}
}
}
73 changes: 73 additions & 0 deletions components/printing/service/pdf_compositor_service.cc
Original file line number Diff line number Diff line change
@@ -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 <utility>

#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<printing::PdfCompositorImpl>(
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<service_manager::Service> PdfCompositorService::Create(
const std::string& creator) {
return base::MakeUnique<printing::PdfCompositorService>(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<service_manager::ServiceContextRefFactory>(
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
Loading

0 comments on commit fabbf75

Please sign in to comment.