Merge pull request #8435 from electron/pdf_rendering
browser: implement native pdf rendering
This commit is contained in:
commit
5200b1a1ab
32 changed files with 1140 additions and 7 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -22,3 +22,6 @@
|
|||
[submodule "vendor/boto"]
|
||||
path = vendor/boto
|
||||
url = https://github.com/boto/boto.git
|
||||
[submodule "vendor/pdf_viewer"]
|
||||
path = vendor/pdf_viewer
|
||||
url = https://github.com/electron/pdf-viewer.git
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "atom/common/atom_version.h"
|
||||
#include "atom/common/chrome_version.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
|
@ -18,6 +19,7 @@
|
|||
#include "content/public/common/content_constants.h"
|
||||
#include "content/public/common/pepper_plugin_info.h"
|
||||
#include "content/public/common/user_agent.h"
|
||||
#include "pdf/pdf.h"
|
||||
#include "ppapi/shared_impl/ppapi_permissions.h"
|
||||
#include "third_party/widevine/cdm/stub/widevine_cdm_version.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
@ -108,6 +110,25 @@ content::PepperPluginInfo CreateWidevineCdmInfo(const base::FilePath& path,
|
|||
}
|
||||
#endif
|
||||
|
||||
void ComputeBuiltInPlugins(std::vector<content::PepperPluginInfo>* plugins) {
|
||||
content::PepperPluginInfo pdf_info;
|
||||
pdf_info.is_internal = true;
|
||||
pdf_info.is_out_of_process = true;
|
||||
pdf_info.name = "Chromium PDF Viewer";
|
||||
pdf_info.description = "Portable Document Format";
|
||||
pdf_info.path = base::FilePath::FromUTF8Unsafe(kPdfPluginPath);
|
||||
content::WebPluginMimeType pdf_mime_type(kPdfPluginMimeType, "pdf",
|
||||
"Portable Document Format");
|
||||
pdf_info.mime_types.push_back(pdf_mime_type);
|
||||
pdf_info.internal_entry_points.get_interface = chrome_pdf::PPP_GetInterface;
|
||||
pdf_info.internal_entry_points.initialize_module =
|
||||
chrome_pdf::PPP_InitializeModule;
|
||||
pdf_info.internal_entry_points.shutdown_module =
|
||||
chrome_pdf::PPP_ShutdownModule;
|
||||
pdf_info.permissions = ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_DEV;
|
||||
plugins->push_back(pdf_info);
|
||||
}
|
||||
|
||||
void ConvertStringWithSeparatorToVector(std::vector<std::string>* vec,
|
||||
const char* separator,
|
||||
const char* cmd_switch) {
|
||||
|
@ -190,6 +211,7 @@ void AtomContentClient::AddPepperPlugins(
|
|||
#if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_PEPPER_CDMS)
|
||||
AddWidevineCdmFromCommandLine(plugins);
|
||||
#endif
|
||||
ComputeBuiltInPlugins(plugins);
|
||||
}
|
||||
|
||||
void AtomContentClient::AddServiceWorkerSchemes(
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "atom/browser/atom_access_token_store.h"
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_web_ui_controller_factory.h"
|
||||
#include "atom/browser/bridge_task_runner.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
|
@ -166,6 +167,9 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
|||
base::Bind(&v8::Isolate::LowMemoryNotification,
|
||||
base::Unretained(js_env_->isolate())));
|
||||
|
||||
content::WebUIControllerFactory::RegisterFactory(
|
||||
AtomWebUIControllerFactory::GetInstance());
|
||||
|
||||
brightray::BrowserMainParts::PreMainMessageLoopRun();
|
||||
bridge_task_runner_->MessageLoopIsReady();
|
||||
bridge_task_runner_ = nullptr;
|
||||
|
|
|
@ -6,11 +6,15 @@
|
|||
|
||||
#include "atom/browser/login_handler.h"
|
||||
#include "atom/browser/web_contents_permission_helper.h"
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "atom/common/platform_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/stream_info.h"
|
||||
#include "net/base/escape.h"
|
||||
#include "net/ssl/client_cert_store.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
#if defined(USE_NSS_CERTS)
|
||||
|
@ -57,6 +61,23 @@ void HandleExternalProtocolInUI(
|
|||
permission_helper->RequestOpenExternalPermission(callback, has_user_gesture);
|
||||
}
|
||||
|
||||
void OnPdfResourceIntercepted(
|
||||
const GURL& original_url,
|
||||
const content::ResourceRequestInfo::WebContentsGetter&
|
||||
web_contents_getter) {
|
||||
content::WebContents* web_contents = web_contents_getter.Run();
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
// The URL passes the original pdf resource url, that will be requested
|
||||
// by the webui page.
|
||||
// chrome://pdf-viewer/index.html?src=https://somepage/123.pdf
|
||||
content::NavigationController::LoadURLParams params(
|
||||
GURL(base::StringPrintf("%sindex.html?%s=%s", kPdfViewerUIOrigin,
|
||||
kPdfPluginSrc, original_url.spec().c_str())));
|
||||
web_contents->GetController().LoadURLWithParams(params);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() {
|
||||
|
@ -95,4 +116,23 @@ AtomResourceDispatcherHostDelegate::CreateClientCertStore(
|
|||
#endif
|
||||
}
|
||||
|
||||
bool AtomResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
|
||||
net::URLRequest* request,
|
||||
const base::FilePath& plugin_path,
|
||||
const std::string& mime_type,
|
||||
GURL* origin,
|
||||
std::string* payload) {
|
||||
const content::ResourceRequestInfo* info =
|
||||
content::ResourceRequestInfo::ForRequest(request);
|
||||
if (mime_type == "application/pdf" && info->IsMainFrame()) {
|
||||
*origin = GURL(kPdfViewerUIOrigin);
|
||||
content::BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&OnPdfResourceIntercepted, request->url(),
|
||||
info->GetWebContentsGetterForRequest()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#ifndef ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
|
||||
#define ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "content/public/browser/resource_dispatcher_host_delegate.h"
|
||||
|
||||
namespace atom {
|
||||
|
@ -22,6 +24,14 @@ class AtomResourceDispatcherHostDelegate
|
|||
net::URLRequest* request) override;
|
||||
std::unique_ptr<net::ClientCertStore> CreateClientCertStore(
|
||||
content::ResourceContext* resource_context) override;
|
||||
bool ShouldInterceptResourceAsStream(net::URLRequest* request,
|
||||
const base::FilePath& plugin_path,
|
||||
const std::string& mime_type,
|
||||
GURL* origin,
|
||||
std::string* payload) override;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomResourceDispatcherHostDelegate);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
|
66
atom/browser/atom_web_ui_controller_factory.cc
Normal file
66
atom/browser/atom_web_ui_controller_factory.cc
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/atom_web_ui_controller_factory.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/ui/webui/pdf_viewer_ui.h"
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// static
|
||||
AtomWebUIControllerFactory* AtomWebUIControllerFactory::GetInstance() {
|
||||
return base::Singleton<AtomWebUIControllerFactory>::get();
|
||||
}
|
||||
|
||||
AtomWebUIControllerFactory::AtomWebUIControllerFactory() {}
|
||||
|
||||
AtomWebUIControllerFactory::~AtomWebUIControllerFactory() {}
|
||||
|
||||
content::WebUI::TypeID AtomWebUIControllerFactory::GetWebUIType(
|
||||
content::BrowserContext* browser_context,
|
||||
const GURL& url) const {
|
||||
if (url.host() == kPdfViewerUIHost) {
|
||||
return const_cast<AtomWebUIControllerFactory*>(this);
|
||||
}
|
||||
|
||||
return content::WebUI::kNoWebUI;
|
||||
}
|
||||
|
||||
bool AtomWebUIControllerFactory::UseWebUIForURL(
|
||||
content::BrowserContext* browser_context,
|
||||
const GURL& url) const {
|
||||
return GetWebUIType(browser_context, url) != content::WebUI::kNoWebUI;
|
||||
}
|
||||
|
||||
bool AtomWebUIControllerFactory::UseWebUIBindingsForURL(
|
||||
content::BrowserContext* browser_context,
|
||||
const GURL& url) const {
|
||||
return UseWebUIForURL(browser_context, url);
|
||||
}
|
||||
|
||||
content::WebUIController*
|
||||
AtomWebUIControllerFactory::CreateWebUIControllerForURL(content::WebUI* web_ui,
|
||||
const GURL& url) const {
|
||||
if (url.host() == kPdfViewerUIHost) {
|
||||
base::StringPairs toplevel_params;
|
||||
base::SplitStringIntoKeyValuePairs(url.query(), '=', '&', &toplevel_params);
|
||||
std::string stream_id, src;
|
||||
for (const auto& param : toplevel_params) {
|
||||
if (param.first == kPdfPluginSrc) {
|
||||
src = param.second;
|
||||
}
|
||||
}
|
||||
auto browser_context = web_ui->GetWebContents()->GetBrowserContext();
|
||||
return new PdfViewerUI(browser_context, web_ui, src);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace atom
|
40
atom/browser/atom_web_ui_controller_factory.h
Normal file
40
atom/browser/atom_web_ui_controller_factory.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_ATOM_WEB_UI_CONTROLLER_FACTORY_H_
|
||||
#define ATOM_BROWSER_ATOM_WEB_UI_CONTROLLER_FACTORY_H_
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include "content/public/browser/web_ui_controller_factory.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomWebUIControllerFactory : public content::WebUIControllerFactory {
|
||||
public:
|
||||
static AtomWebUIControllerFactory* GetInstance();
|
||||
|
||||
AtomWebUIControllerFactory();
|
||||
virtual ~AtomWebUIControllerFactory();
|
||||
|
||||
// content::WebUIControllerFactory:
|
||||
content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
|
||||
const GURL& url) const override;
|
||||
bool UseWebUIForURL(content::BrowserContext* browser_context,
|
||||
const GURL& url) const override;
|
||||
bool UseWebUIBindingsForURL(content::BrowserContext* browser_context,
|
||||
const GURL& url) const override;
|
||||
content::WebUIController* CreateWebUIControllerForURL(
|
||||
content::WebUI* web_ui,
|
||||
const GURL& url) const override;
|
||||
|
||||
private:
|
||||
friend struct base::DefaultSingletonTraits<AtomWebUIControllerFactory>;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomWebUIControllerFactory);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_ATOM_WEB_UI_CONTROLLER_FACTORY_H_
|
26
atom/browser/loader/layered_resource_handler.cc
Normal file
26
atom/browser/loader/layered_resource_handler.cc
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/loader/layered_resource_handler.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
LayeredResourceHandler::LayeredResourceHandler(
|
||||
net::URLRequest* request,
|
||||
std::unique_ptr<content::ResourceHandler> next_handler,
|
||||
Delegate* delegate)
|
||||
: content::LayeredResourceHandler(request, std::move(next_handler)),
|
||||
delegate_(delegate) {}
|
||||
|
||||
LayeredResourceHandler::~LayeredResourceHandler() {}
|
||||
|
||||
bool LayeredResourceHandler::OnResponseStarted(
|
||||
content::ResourceResponse* response,
|
||||
bool* defer) {
|
||||
if (delegate_)
|
||||
delegate_->OnResponseStarted(response);
|
||||
return next_handler_->OnResponseStarted(response, defer);
|
||||
}
|
||||
|
||||
} // namespace atom
|
40
atom/browser/loader/layered_resource_handler.h
Normal file
40
atom/browser/loader/layered_resource_handler.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
|
||||
#define ATOM_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
|
||||
|
||||
#include "content/browser/loader/layered_resource_handler.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Resource handler that notifies on various stages of a resource request.
|
||||
class LayeredResourceHandler : public content::LayeredResourceHandler {
|
||||
public:
|
||||
class Delegate {
|
||||
public:
|
||||
Delegate() {}
|
||||
virtual ~Delegate() {}
|
||||
|
||||
virtual void OnResponseStarted(content::ResourceResponse* response) = 0;
|
||||
};
|
||||
|
||||
LayeredResourceHandler(net::URLRequest* request,
|
||||
std::unique_ptr<content::ResourceHandler> next_handler,
|
||||
Delegate* delegate);
|
||||
~LayeredResourceHandler() override;
|
||||
|
||||
// content::LayeredResourceHandler:
|
||||
bool OnResponseStarted(content::ResourceResponse* response,
|
||||
bool* defer) override;
|
||||
|
||||
private:
|
||||
Delegate* delegate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LayeredResourceHandler);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
|
212
atom/browser/ui/webui/pdf_viewer_handler.cc
Normal file
212
atom/browser/ui/webui/pdf_viewer_handler.cc
Normal file
|
@ -0,0 +1,212 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/webui/pdf_viewer_handler.h"
|
||||
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/values.h"
|
||||
#include "content/public/browser/stream_handle.h"
|
||||
#include "content/public/browser/stream_info.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_ui.h"
|
||||
#include "content/public/common/page_zoom.h"
|
||||
#include "content/public/common/url_constants.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/webui/web_ui_util.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
void CreateResponseHeadersDictionary(const net::HttpResponseHeaders* headers,
|
||||
base::DictionaryValue* result) {
|
||||
if (!headers)
|
||||
return;
|
||||
|
||||
size_t iter = 0;
|
||||
std::string header_name;
|
||||
std::string header_value;
|
||||
while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) {
|
||||
base::Value* existing_value = nullptr;
|
||||
if (result->Get(header_name, &existing_value)) {
|
||||
base::StringValue* existing_string_value =
|
||||
static_cast<base::StringValue*>(existing_value);
|
||||
existing_string_value->GetString()->append(", ").append(header_value);
|
||||
} else {
|
||||
result->SetString(header_name, header_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PopulateStreamInfo(base::DictionaryValue* stream_info,
|
||||
content::StreamInfo* stream,
|
||||
const std::string& original_url) {
|
||||
auto headers_dict = base::MakeUnique<base::DictionaryValue>();
|
||||
auto stream_url = stream->handle->GetURL().spec();
|
||||
CreateResponseHeadersDictionary(stream->response_headers.get(),
|
||||
headers_dict.get());
|
||||
stream_info->SetString("streamURL", stream_url);
|
||||
stream_info->SetString("originalURL", original_url);
|
||||
stream_info->Set("responseHeaders", std::move(headers_dict));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PdfViewerHandler::PdfViewerHandler(const std::string& src)
|
||||
: stream_(nullptr), original_url_(src) {}
|
||||
|
||||
PdfViewerHandler::~PdfViewerHandler() {}
|
||||
|
||||
void PdfViewerHandler::SetPdfResourceStream(content::StreamInfo* stream) {
|
||||
stream_ = stream;
|
||||
if (!!initialize_callback_id_.get()) {
|
||||
auto list = base::MakeUnique<base::ListValue>();
|
||||
list->Set(0, std::move(initialize_callback_id_));
|
||||
Initialize(list.get());
|
||||
}
|
||||
}
|
||||
|
||||
void PdfViewerHandler::RegisterMessages() {
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"initialize",
|
||||
base::Bind(&PdfViewerHandler::Initialize, base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"getDefaultZoom",
|
||||
base::Bind(&PdfViewerHandler::GetInitialZoom, base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"getInitialZoom",
|
||||
base::Bind(&PdfViewerHandler::GetInitialZoom, base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"setZoom",
|
||||
base::Bind(&PdfViewerHandler::SetZoom, base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"getStrings",
|
||||
base::Bind(&PdfViewerHandler::GetStrings, base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"reload", base::Bind(&PdfViewerHandler::Reload, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void PdfViewerHandler::OnJavascriptAllowed() {
|
||||
auto host_zoom_map =
|
||||
content::HostZoomMap::GetForWebContents(web_ui()->GetWebContents());
|
||||
host_zoom_map_subscription_ =
|
||||
host_zoom_map->AddZoomLevelChangedCallback(base::Bind(
|
||||
&PdfViewerHandler::OnZoomLevelChanged, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void PdfViewerHandler::OnJavascriptDisallowed() {
|
||||
host_zoom_map_subscription_.reset();
|
||||
}
|
||||
|
||||
void PdfViewerHandler::Initialize(const base::ListValue* args) {
|
||||
CHECK_EQ(1U, args->GetSize());
|
||||
const base::Value* callback_id;
|
||||
CHECK(args->Get(0, &callback_id));
|
||||
|
||||
if (stream_) {
|
||||
CHECK(!initialize_callback_id_.get());
|
||||
AllowJavascript();
|
||||
|
||||
auto stream_info = base::MakeUnique<base::DictionaryValue>();
|
||||
PopulateStreamInfo(stream_info.get(), stream_, original_url_);
|
||||
ResolveJavascriptCallback(*callback_id, *stream_info);
|
||||
} else {
|
||||
initialize_callback_id_ = callback_id->CreateDeepCopy();
|
||||
}
|
||||
}
|
||||
|
||||
void PdfViewerHandler::GetDefaultZoom(const base::ListValue* args) {
|
||||
if (!IsJavascriptAllowed())
|
||||
return;
|
||||
CHECK_EQ(1U, args->GetSize());
|
||||
const base::Value* callback_id;
|
||||
CHECK(args->Get(0, &callback_id));
|
||||
|
||||
auto host_zoom_map =
|
||||
content::HostZoomMap::GetForWebContents(web_ui()->GetWebContents());
|
||||
double zoom_level = host_zoom_map->GetDefaultZoomLevel();
|
||||
ResolveJavascriptCallback(
|
||||
*callback_id,
|
||||
base::FundamentalValue(content::ZoomLevelToZoomFactor(zoom_level)));
|
||||
}
|
||||
|
||||
void PdfViewerHandler::GetInitialZoom(const base::ListValue* args) {
|
||||
if (!IsJavascriptAllowed())
|
||||
return;
|
||||
CHECK_EQ(1U, args->GetSize());
|
||||
const base::Value* callback_id;
|
||||
CHECK(args->Get(0, &callback_id));
|
||||
|
||||
double zoom_level =
|
||||
content::HostZoomMap::GetZoomLevel(web_ui()->GetWebContents());
|
||||
ResolveJavascriptCallback(
|
||||
*callback_id,
|
||||
base::FundamentalValue(content::ZoomLevelToZoomFactor(zoom_level)));
|
||||
}
|
||||
|
||||
void PdfViewerHandler::SetZoom(const base::ListValue* args) {
|
||||
if (!IsJavascriptAllowed())
|
||||
return;
|
||||
CHECK_EQ(2U, args->GetSize());
|
||||
const base::Value* callback_id;
|
||||
CHECK(args->Get(0, &callback_id));
|
||||
double zoom_level = 0.0;
|
||||
CHECK(args->GetDouble(1, &zoom_level));
|
||||
|
||||
content::HostZoomMap::SetZoomLevel(web_ui()->GetWebContents(),
|
||||
zoom_level);
|
||||
ResolveJavascriptCallback(*callback_id, base::FundamentalValue(zoom_level));
|
||||
}
|
||||
|
||||
void PdfViewerHandler::GetStrings(const base::ListValue* args) {
|
||||
if (!IsJavascriptAllowed())
|
||||
return;
|
||||
CHECK_EQ(1U, args->GetSize());
|
||||
const base::Value* callback_id;
|
||||
CHECK(args->Get(0, &callback_id));
|
||||
|
||||
auto result = base::MakeUnique<base::DictionaryValue>();
|
||||
// TODO(deepak1556): Generate strings from components/pdf_strings.grdp.
|
||||
#define SET_STRING(id, resource) result->SetString(id, resource)
|
||||
SET_STRING("passwordPrompt",
|
||||
"This document is password protected. Please enter a password.");
|
||||
SET_STRING("passwordSubmit", "Submit");
|
||||
SET_STRING("passwordInvalid", "Incorrect password");
|
||||
SET_STRING("pageLoading", "Loading...");
|
||||
SET_STRING("pageLoadFailed", "Failed to load PDF document");
|
||||
SET_STRING("pageReload", "Reload");
|
||||
SET_STRING("bookmarks", "Bookmarks");
|
||||
SET_STRING("labelPageNumber", "Page number");
|
||||
SET_STRING("tooltipRotateCW", "Rotate clockwise");
|
||||
SET_STRING("tooltipDownload", "Download");
|
||||
SET_STRING("tooltipFitToPage", "Fit to page");
|
||||
SET_STRING("tooltipFitToWidth", "Fit to width");
|
||||
SET_STRING("tooltipZoomIn", "Zoom in");
|
||||
SET_STRING("tooltipZoomOut", "Zoom out");
|
||||
#undef SET_STRING
|
||||
|
||||
webui::SetLoadTimeDataDefaults(l10n_util::GetApplicationLocale(""),
|
||||
result.get());
|
||||
ResolveJavascriptCallback(*callback_id, *result);
|
||||
}
|
||||
|
||||
void PdfViewerHandler::Reload(const base::ListValue* args) {
|
||||
CHECK_EQ(0U, args->GetSize());
|
||||
web_ui()->GetWebContents()->ReloadFocusedFrame(false);
|
||||
}
|
||||
|
||||
void PdfViewerHandler::OnZoomLevelChanged(
|
||||
const content::HostZoomMap::ZoomLevelChange& change) {
|
||||
if (change.host == kPdfViewerUIHost) {
|
||||
CallJavascriptFunction(
|
||||
"cr.webUIListenerCallback", base::StringValue("onZoomLevelChanged"),
|
||||
base::FundamentalValue(
|
||||
content::ZoomLevelToZoomFactor(change.zoom_level)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
58
atom/browser/ui/webui/pdf_viewer_handler.h
Normal file
58
atom/browser/ui/webui/pdf_viewer_handler.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_WEBUI_PDF_VIEWER_HANDLER_H_
|
||||
#define ATOM_BROWSER_UI_WEBUI_PDF_VIEWER_HANDLER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "content/public/browser/host_zoom_map.h"
|
||||
#include "content/public/browser/web_ui_message_handler.h"
|
||||
|
||||
namespace base {
|
||||
class ListValue;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
struct StreamInfo;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class PdfViewerHandler : public content::WebUIMessageHandler {
|
||||
public:
|
||||
explicit PdfViewerHandler(const std::string& original_url);
|
||||
~PdfViewerHandler() override;
|
||||
|
||||
void SetPdfResourceStream(content::StreamInfo* stream);
|
||||
|
||||
protected:
|
||||
// WebUIMessageHandler implementation.
|
||||
void RegisterMessages() override;
|
||||
void OnJavascriptAllowed() override;
|
||||
void OnJavascriptDisallowed() override;
|
||||
|
||||
private:
|
||||
void Initialize(const base::ListValue* args);
|
||||
void GetDefaultZoom(const base::ListValue* args);
|
||||
void GetInitialZoom(const base::ListValue* args);
|
||||
void SetZoom(const base::ListValue* args);
|
||||
void GetStrings(const base::ListValue* args);
|
||||
void Reload(const base::ListValue* args);
|
||||
void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change);
|
||||
|
||||
// Keeps track of events related to zooming.
|
||||
std::unique_ptr<content::HostZoomMap::Subscription>
|
||||
host_zoom_map_subscription_;
|
||||
std::unique_ptr<base::Value> initialize_callback_id_;
|
||||
content::StreamInfo* stream_;
|
||||
std::string original_url_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PdfViewerHandler);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_WEBUI_PDF_VIEWER_HANDLER_H_
|
251
atom/browser/ui/webui/pdf_viewer_ui.cc
Normal file
251
atom/browser/ui/webui/pdf_viewer_ui.cc
Normal file
|
@ -0,0 +1,251 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/webui/pdf_viewer_ui.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/loader/layered_resource_handler.h"
|
||||
#include "atom/browser/ui/webui/pdf_viewer_handler.h"
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "base/sequenced_task_runner_helpers.h"
|
||||
#include "components/pdf/common/pdf_messages.h"
|
||||
#include "content/browser/loader/resource_dispatcher_host_impl.h"
|
||||
#include "content/browser/loader/resource_request_info_impl.h"
|
||||
#include "content/browser/loader/stream_resource_handler.h"
|
||||
#include "content/browser/resource_context_impl.h"
|
||||
#include "content/browser/streams/stream.h"
|
||||
#include "content/browser/streams/stream_context.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/resource_context.h"
|
||||
#include "content/public/browser/stream_handle.h"
|
||||
#include "content/public/browser/stream_info.h"
|
||||
#include "content/public/browser/url_data_source.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "grit/pdf_viewer_resources_map.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "ui/base/resource/resource_bundle.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Extracts the path value from the URL without the leading '/',
|
||||
// which follows the mapping of names in pdf_viewer_resources_map.
|
||||
std::string PathWithoutParams(const std::string& path) {
|
||||
return GURL(kPdfViewerUIOrigin + path).path().substr(1);
|
||||
}
|
||||
|
||||
class BundledDataSource : public content::URLDataSource {
|
||||
public:
|
||||
BundledDataSource() {
|
||||
for (size_t i = 0; i < kPdfViewerResourcesSize; ++i) {
|
||||
std::string resource_path = kPdfViewerResources[i].name;
|
||||
DCHECK(path_to_resource_id_.find(resource_path) ==
|
||||
path_to_resource_id_.end());
|
||||
path_to_resource_id_[resource_path] = kPdfViewerResources[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
// content::URLDataSource implementation.
|
||||
std::string GetSource() const override { return kPdfViewerUIHost; }
|
||||
|
||||
void StartDataRequest(
|
||||
const std::string& path,
|
||||
const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
|
||||
const GotDataCallback& callback) override {
|
||||
std::string filename = PathWithoutParams(path);
|
||||
auto entry = path_to_resource_id_.find(filename);
|
||||
|
||||
if (entry != path_to_resource_id_.end()) {
|
||||
int resource_id = entry->second;
|
||||
const ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
||||
callback.Run(rb.LoadDataResourceBytes(resource_id));
|
||||
} else {
|
||||
LOG(ERROR) << "Unable to find: " << path;
|
||||
callback.Run(new base::RefCountedString());
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetMimeType(const std::string& path) const override {
|
||||
std::string filename = PathWithoutParams(path);
|
||||
std::string mime_type;
|
||||
net::GetMimeTypeFromFile(
|
||||
base::FilePath::FromUTF8Unsafe(filename), &mime_type);
|
||||
return mime_type;
|
||||
}
|
||||
|
||||
bool ShouldAddContentSecurityPolicy() const override { return false; }
|
||||
|
||||
bool ShouldDenyXFrameOptions() const override { return false; }
|
||||
|
||||
bool ShouldServeMimeTypeAsContentTypeHeader() const override { return true; }
|
||||
|
||||
private:
|
||||
~BundledDataSource() override {}
|
||||
|
||||
// A map from a resource path to the resource ID.
|
||||
std::map<std::string, int> path_to_resource_id_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BundledDataSource);
|
||||
};
|
||||
|
||||
// Helper to convert from OnceCallback to Callback.
|
||||
template <typename T>
|
||||
void CallMigrationCallback(T callback,
|
||||
std::unique_ptr<content::StreamInfo> stream_info) {
|
||||
std::move(callback).Run(std::move(stream_info));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class PdfViewerUI::ResourceRequester
|
||||
: public base::RefCountedThreadSafe<ResourceRequester,
|
||||
BrowserThread::DeleteOnIOThread>,
|
||||
public atom::LayeredResourceHandler::Delegate {
|
||||
public:
|
||||
explicit ResourceRequester(StreamResponseCallback cb)
|
||||
: stream_response_cb_(std::move(cb)) {}
|
||||
|
||||
void StartRequest(const GURL& url,
|
||||
const GURL& origin,
|
||||
int render_process_id,
|
||||
int render_view_id,
|
||||
int render_frame_id,
|
||||
content::ResourceContext* resource_context) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
const net::URLRequestContext* request_context =
|
||||
resource_context->GetRequestContext();
|
||||
std::unique_ptr<net::URLRequest> request(
|
||||
request_context->CreateRequest(url, net::DEFAULT_PRIORITY, nullptr));
|
||||
request->set_method("GET");
|
||||
|
||||
content::ResourceDispatcherHostImpl::Get()->InitializeURLRequest(
|
||||
request.get(), content::Referrer(url, blink::WebReferrerPolicyDefault),
|
||||
false, // download.
|
||||
render_process_id, render_view_id, render_frame_id, resource_context);
|
||||
|
||||
content::ResourceRequestInfoImpl* info =
|
||||
content::ResourceRequestInfoImpl::ForRequest(request.get());
|
||||
content::StreamContext* stream_context =
|
||||
content::GetStreamContextForResourceContext(resource_context);
|
||||
|
||||
std::unique_ptr<content::ResourceHandler> handler =
|
||||
base::MakeUnique<content::StreamResourceHandler>(
|
||||
request.get(), stream_context->registry(), origin);
|
||||
info->set_is_stream(true);
|
||||
stream_info_.reset(new content::StreamInfo);
|
||||
stream_info_->handle =
|
||||
static_cast<content::StreamResourceHandler*>(handler.get())
|
||||
->stream()
|
||||
->CreateHandle();
|
||||
stream_info_->original_url = request->url();
|
||||
|
||||
// Helper to fill stream response details.
|
||||
handler.reset(new atom::LayeredResourceHandler(request.get(),
|
||||
std::move(handler), this));
|
||||
|
||||
content::ResourceDispatcherHostImpl::Get()->BeginURLRequest(
|
||||
std::move(request), std::move(handler),
|
||||
false, // download
|
||||
false, // content_initiated (download specific)
|
||||
false, // do_not_prompt_for_login (download specific)
|
||||
resource_context);
|
||||
}
|
||||
|
||||
protected:
|
||||
// atom::LayeredResourceHandler::Delegate:
|
||||
void OnResponseStarted(content::ResourceResponse* response) override {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
auto resource_response_head = response->head;
|
||||
auto headers = resource_response_head.headers;
|
||||
auto mime_type = resource_response_head.mime_type;
|
||||
if (headers.get())
|
||||
stream_info_->response_headers =
|
||||
new net::HttpResponseHeaders(headers->raw_headers());
|
||||
stream_info_->mime_type = mime_type;
|
||||
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&CallMigrationCallback<StreamResponseCallback>,
|
||||
base::Passed(&stream_response_cb_),
|
||||
base::Passed(&stream_info_)));
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
|
||||
friend class base::DeleteHelper<ResourceRequester>;
|
||||
~ResourceRequester() override {}
|
||||
|
||||
StreamResponseCallback stream_response_cb_;
|
||||
std::unique_ptr<content::StreamInfo> stream_info_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ResourceRequester);
|
||||
};
|
||||
|
||||
PdfViewerUI::PdfViewerUI(content::BrowserContext* browser_context,
|
||||
content::WebUI* web_ui,
|
||||
const std::string& src)
|
||||
: content::WebUIController(web_ui),
|
||||
content::WebContentsObserver(web_ui->GetWebContents()),
|
||||
src_(src) {
|
||||
pdf_handler_ = new PdfViewerHandler(src);
|
||||
web_ui->AddMessageHandler(pdf_handler_);
|
||||
content::URLDataSource::Add(browser_context, new BundledDataSource);
|
||||
}
|
||||
|
||||
PdfViewerUI::~PdfViewerUI() {}
|
||||
|
||||
bool PdfViewerUI::OnMessageReceived(
|
||||
const IPC::Message& message,
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
bool handled = true;
|
||||
IPC_BEGIN_MESSAGE_MAP(PdfViewerUI, message)
|
||||
IPC_MESSAGE_HANDLER(PDFHostMsg_PDFSaveURLAs, OnSaveURLAs)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
return handled;
|
||||
}
|
||||
|
||||
void PdfViewerUI::OnPdfStreamCreated(
|
||||
std::unique_ptr<content::StreamInfo> stream) {
|
||||
stream_ = std::move(stream);
|
||||
if (pdf_handler_)
|
||||
pdf_handler_->SetPdfResourceStream(stream_.get());
|
||||
resource_requester_ = nullptr;
|
||||
}
|
||||
|
||||
void PdfViewerUI::RenderFrameCreated(content::RenderFrameHost* rfh) {
|
||||
int render_process_id = rfh->GetProcess()->GetID();
|
||||
int render_frame_id = rfh->GetRoutingID();
|
||||
int render_view_id = rfh->GetRenderViewHost()->GetRoutingID();
|
||||
auto resource_context =
|
||||
web_contents()->GetBrowserContext()->GetResourceContext();
|
||||
auto callback =
|
||||
base::BindOnce(&PdfViewerUI::OnPdfStreamCreated, base::Unretained(this));
|
||||
resource_requester_ = new ResourceRequester(std::move(callback));
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&ResourceRequester::StartRequest, resource_requester_,
|
||||
GURL(src_), GURL(kPdfViewerUIOrigin), render_process_id,
|
||||
render_view_id, render_frame_id, resource_context));
|
||||
}
|
||||
|
||||
void PdfViewerUI::OnSaveURLAs(const GURL& url,
|
||||
const content::Referrer& referrer) {
|
||||
web_contents()->SaveFrame(url, referrer);
|
||||
}
|
||||
|
||||
} // namespace atom
|
60
atom/browser/ui/webui/pdf_viewer_ui.h
Normal file
60
atom/browser/ui/webui/pdf_viewer_ui.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_WEBUI_PDF_VIEWER_UI_H_
|
||||
#define ATOM_BROWSER_UI_WEBUI_PDF_VIEWER_UI_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/browser/web_ui_controller.h"
|
||||
#include "ipc/ipc_message.h"
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
struct StreamInfo;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class PdfViewerHandler;
|
||||
|
||||
class PdfViewerUI : public content::WebUIController,
|
||||
public content::WebContentsObserver {
|
||||
public:
|
||||
PdfViewerUI(content::BrowserContext* browser_context,
|
||||
content::WebUI* web_ui,
|
||||
const std::string& src);
|
||||
~PdfViewerUI() override;
|
||||
|
||||
// content::WebContentsObserver:
|
||||
bool OnMessageReceived(const IPC::Message& message,
|
||||
content::RenderFrameHost* render_frame_host) override;
|
||||
void RenderFrameCreated(content::RenderFrameHost* rfh) override;
|
||||
|
||||
private:
|
||||
using StreamResponseCallback =
|
||||
base::OnceCallback<void(std::unique_ptr<content::StreamInfo>)>;
|
||||
class ResourceRequester;
|
||||
|
||||
void OnPdfStreamCreated(std::unique_ptr<content::StreamInfo> stream_info);
|
||||
void OnSaveURLAs(const GURL& url, const content::Referrer& referrer);
|
||||
|
||||
// Source URL from where the PDF originates.
|
||||
std::string src_;
|
||||
|
||||
PdfViewerHandler* pdf_handler_;
|
||||
|
||||
scoped_refptr<ResourceRequester> resource_requester_;
|
||||
|
||||
// Pdf Resource stream.
|
||||
std::unique_ptr<content::StreamInfo> stream_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PdfViewerUI);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_WEBUI_PDF_VIEWER_UI_H_
|
|
@ -24,4 +24,11 @@ const char kSecureProtocolDescription[] =
|
|||
"The connection to this site is using a strong protocol version "
|
||||
"and cipher suite.";
|
||||
|
||||
const char kPdfPluginMimeType[] = "application/x-google-chrome-pdf";
|
||||
const char kPdfPluginPath[] = "chrome://pdf-viewer/";
|
||||
const char kPdfPluginSrc[] = "src";
|
||||
|
||||
const char kPdfViewerUIOrigin[] = "chrome://pdf-viewer/";
|
||||
const char kPdfViewerUIHost[] = "pdf-viewer";
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -20,6 +20,15 @@ extern const char kValidCertificateDescription[];
|
|||
extern const char kSecureProtocol[];
|
||||
extern const char kSecureProtocolDescription[];
|
||||
|
||||
// The MIME type used for the PDF plugin.
|
||||
extern const char kPdfPluginMimeType[];
|
||||
extern const char kPdfPluginPath[];
|
||||
extern const char kPdfPluginSrc[];
|
||||
|
||||
// Constants for PDF viewer webui.
|
||||
extern const char kPdfViewerUIOrigin[];
|
||||
extern const char kPdfViewerUIHost[];
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_ATOM_CONSTANTS_H_
|
||||
|
|
|
@ -9,3 +9,4 @@
|
|||
#include "chrome/common/tts_messages.h"
|
||||
#include "chrome/common/widevine_cdm_messages.h"
|
||||
#include "chrome/common/chrome_utility_messages.h"
|
||||
#include "components/pdf/common/pdf_messages.h"
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/api/atom_bindings.h"
|
||||
#include "atom/common/api/event_emitter_caller.h"
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "atom/common/color_util.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "atom/common/node_bindings.h"
|
||||
|
@ -274,6 +275,10 @@ void AtomRendererClient::RenderFrameCreated(
|
|||
// This is required for widevine plugin detection provided during runtime.
|
||||
blink::resetPluginCache();
|
||||
|
||||
// Allow access to file scheme from pdf viewer.
|
||||
blink::WebSecurityPolicy::addOriginAccessWhitelistEntry(
|
||||
GURL(kPdfViewerUIOrigin), "file", "", true);
|
||||
|
||||
// Parse --secure-schemes=scheme1,scheme2
|
||||
std::vector<std::string> secure_schemes_list =
|
||||
ParseSchemesCLISwitch(switches::kSecureSchemes);
|
||||
|
@ -339,6 +344,7 @@ bool AtomRendererClient::OverrideCreatePlugin(
|
|||
blink::WebPlugin** plugin) {
|
||||
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
||||
if (params.mimeType.utf8() == content::kBrowserPluginMimeType ||
|
||||
params.mimeType.utf8() == kPdfPluginMimeType ||
|
||||
command_line->HasSwitch(switches::kEnablePlugins))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
#include "chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "chrome/renderer/pepper/pepper_flash_font_file_host.h"
|
||||
#include "chrome/renderer/pepper/pepper_flash_fullscreen_host.h"
|
||||
#include "chrome/renderer/pepper/pepper_flash_menu_host.h"
|
||||
#include "chrome/renderer/pepper/pepper_flash_renderer_host.h"
|
||||
#include "components/pdf/renderer/pepper_pdf_host.h"
|
||||
#include "content/public/renderer/renderer_ppapi_host.h"
|
||||
#include "ppapi/host/ppapi_host.h"
|
||||
#include "ppapi/host/resource_host.h"
|
||||
|
@ -79,5 +81,14 @@ std::unique_ptr<ResourceHost> ChromeRendererPepperHostFactory::CreateResourceHos
|
|||
}
|
||||
}
|
||||
|
||||
if (host_->GetPpapiHost()->permissions().HasPermission(
|
||||
ppapi::PERMISSION_PRIVATE)) {
|
||||
switch (message.type()) {
|
||||
case PpapiHostMsg_PDF_Create::ID: {
|
||||
return base::MakeUnique<pdf::PepperPDFHost>(host_, instance, resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<ResourceHost>();
|
||||
}
|
||||
|
|
19
chromium_src/components/pdf/common/pdf_messages.h
Normal file
19
chromium_src/components/pdf/common/pdf_messages.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
// Multiply-included file, no traditional include guard.
|
||||
#include <string.h>
|
||||
|
||||
#include "content/public/common/common_param_traits_macros.h"
|
||||
#include "content/public/common/referrer.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
#include "url/gurl.h"
|
||||
#include "url/ipc/url_param_traits.h"
|
||||
|
||||
#define IPC_MESSAGE_START PDFMsgStart
|
||||
|
||||
// Brings up SaveAs... dialog to save specified URL.
|
||||
IPC_MESSAGE_ROUTED2(PDFHostMsg_PDFSaveURLAs,
|
||||
GURL /* url */,
|
||||
content::Referrer /* referrer */)
|
113
chromium_src/components/pdf/renderer/pepper_pdf_host.cc
Normal file
113
chromium_src/components/pdf/renderer/pepper_pdf_host.cc
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Copyright 2014 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/pdf/renderer/pepper_pdf_host.h"
|
||||
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "components/pdf/common/pdf_messages.h"
|
||||
#include "content/public/common/referrer.h"
|
||||
#include "content/public/renderer/pepper_plugin_instance.h"
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
#include "content/public/renderer/renderer_ppapi_host.h"
|
||||
#include "ppapi/host/dispatch_host_message.h"
|
||||
#include "ppapi/proxy/ppapi_messages.h"
|
||||
|
||||
namespace pdf {
|
||||
|
||||
PepperPDFHost::PepperPDFHost(content::RendererPpapiHost* host,
|
||||
PP_Instance instance,
|
||||
PP_Resource resource)
|
||||
: ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource),
|
||||
host_(host) {}
|
||||
|
||||
PepperPDFHost::~PepperPDFHost() {}
|
||||
|
||||
int32_t PepperPDFHost::OnResourceMessageReceived(
|
||||
const IPC::Message& msg,
|
||||
ppapi::host::HostMessageContext* context) {
|
||||
PPAPI_BEGIN_MESSAGE_MAP(PepperPDFHost, msg)
|
||||
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_DidStartLoading,
|
||||
OnHostMsgDidStartLoading)
|
||||
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_DidStopLoading,
|
||||
OnHostMsgDidStopLoading)
|
||||
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_SaveAs,
|
||||
OnHostMsgSaveAs)
|
||||
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_SetSelectedText,
|
||||
OnHostMsgSetSelectedText)
|
||||
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_SetLinkUnderCursor,
|
||||
OnHostMsgSetLinkUnderCursor)
|
||||
PPAPI_END_MESSAGE_MAP()
|
||||
return PP_ERROR_FAILED;
|
||||
}
|
||||
|
||||
int32_t PepperPDFHost::OnHostMsgDidStartLoading(
|
||||
ppapi::host::HostMessageContext* context) {
|
||||
content::RenderFrame* render_frame = GetRenderFrame();
|
||||
if (!render_frame)
|
||||
return PP_ERROR_FAILED;
|
||||
|
||||
render_frame->DidStartLoading();
|
||||
return PP_OK;
|
||||
}
|
||||
|
||||
int32_t PepperPDFHost::OnHostMsgDidStopLoading(
|
||||
ppapi::host::HostMessageContext* context) {
|
||||
content::RenderFrame* render_frame = GetRenderFrame();
|
||||
if (!render_frame)
|
||||
return PP_ERROR_FAILED;
|
||||
|
||||
render_frame->DidStopLoading();
|
||||
return PP_OK;
|
||||
}
|
||||
|
||||
int32_t PepperPDFHost::OnHostMsgSaveAs(
|
||||
ppapi::host::HostMessageContext* context) {
|
||||
content::PepperPluginInstance* instance =
|
||||
host_->GetPluginInstance(pp_instance());
|
||||
if (!instance)
|
||||
return PP_ERROR_FAILED;
|
||||
|
||||
content::RenderFrame* render_frame = instance->GetRenderFrame();
|
||||
if (!render_frame)
|
||||
return PP_ERROR_FAILED;
|
||||
|
||||
GURL url = instance->GetPluginURL();
|
||||
content::Referrer referrer;
|
||||
referrer.url = url;
|
||||
referrer.policy = blink::WebReferrerPolicyDefault;
|
||||
referrer = content::Referrer::SanitizeForRequest(url, referrer);
|
||||
render_frame->Send(
|
||||
new PDFHostMsg_PDFSaveURLAs(render_frame->GetRoutingID(), url, referrer));
|
||||
return PP_OK;
|
||||
}
|
||||
|
||||
int32_t PepperPDFHost::OnHostMsgSetSelectedText(
|
||||
ppapi::host::HostMessageContext* context,
|
||||
const base::string16& selected_text) {
|
||||
content::PepperPluginInstance* instance =
|
||||
host_->GetPluginInstance(pp_instance());
|
||||
if (!instance)
|
||||
return PP_ERROR_FAILED;
|
||||
instance->SetSelectedText(selected_text);
|
||||
return PP_OK;
|
||||
}
|
||||
|
||||
int32_t PepperPDFHost::OnHostMsgSetLinkUnderCursor(
|
||||
ppapi::host::HostMessageContext* context,
|
||||
const std::string& url) {
|
||||
content::PepperPluginInstance* instance =
|
||||
host_->GetPluginInstance(pp_instance());
|
||||
if (!instance)
|
||||
return PP_ERROR_FAILED;
|
||||
instance->SetLinkUnderCursor(url);
|
||||
return PP_OK;
|
||||
}
|
||||
|
||||
content::RenderFrame* PepperPDFHost::GetRenderFrame() {
|
||||
content::PepperPluginInstance* instance =
|
||||
host_->GetPluginInstance(pp_instance());
|
||||
return instance ? instance->GetRenderFrame() : nullptr;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
52
chromium_src/components/pdf/renderer/pepper_pdf_host.h
Normal file
52
chromium_src/components/pdf/renderer/pepper_pdf_host.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2014 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_PDF_RENDERER_PEPPER_PDF_HOST_H_
|
||||
#define COMPONENTS_PDF_RENDERER_PEPPER_PDF_HOST_H_
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "ppapi/host/resource_host.h"
|
||||
|
||||
namespace content {
|
||||
class RenderFrame;
|
||||
class RendererPpapiHost;
|
||||
}
|
||||
|
||||
namespace pdf {
|
||||
|
||||
class PdfAccessibilityTree;
|
||||
|
||||
class PepperPDFHost : public ppapi::host::ResourceHost {
|
||||
public:
|
||||
PepperPDFHost(content::RendererPpapiHost* host,
|
||||
PP_Instance instance,
|
||||
PP_Resource resource);
|
||||
~PepperPDFHost() override;
|
||||
|
||||
// ppapi::host::ResourceHost:
|
||||
int32_t OnResourceMessageReceived(
|
||||
const IPC::Message& msg,
|
||||
ppapi::host::HostMessageContext* context) override;
|
||||
|
||||
private:
|
||||
int32_t OnHostMsgDidStartLoading(ppapi::host::HostMessageContext* context);
|
||||
int32_t OnHostMsgDidStopLoading(ppapi::host::HostMessageContext* context);
|
||||
int32_t OnHostMsgSaveAs(ppapi::host::HostMessageContext* context);
|
||||
int32_t OnHostMsgSetSelectedText(ppapi::host::HostMessageContext* context,
|
||||
const base::string16& selected_text);
|
||||
int32_t OnHostMsgSetLinkUnderCursor(ppapi::host::HostMessageContext* context,
|
||||
const std::string& url);
|
||||
|
||||
content::RenderFrame* GetRenderFrame();
|
||||
|
||||
content::RendererPpapiHost* const host_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PepperPDFHost);
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // COMPONENTS_PDF_RENDERER_PEPPER_PDF_HOST_H_
|
|
@ -210,6 +210,7 @@
|
|||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'atom_js2c',
|
||||
'vendor/pdf_viewer/pdf_viewer.gyp:pdf_viewer',
|
||||
'vendor/brightray/brightray.gyp:brightray',
|
||||
'vendor/node/node.gyp:node',
|
||||
],
|
||||
|
@ -543,6 +544,7 @@
|
|||
'<(libchromiumcontent_dir)/icudtl.dat',
|
||||
'<(libchromiumcontent_dir)/natives_blob.bin',
|
||||
'<(libchromiumcontent_dir)/snapshot_blob.bin',
|
||||
'<(PRODUCT_DIR)/pdf_viewer_resources.pak',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'ATOM_BUNDLE_ID': 'com.<(company_abbr).<(project_name).framework',
|
||||
|
|
|
@ -195,6 +195,8 @@
|
|||
'atom/browser/atom_resource_dispatcher_host_delegate.h',
|
||||
'atom/browser/atom_speech_recognition_manager_delegate.cc',
|
||||
'atom/browser/atom_speech_recognition_manager_delegate.h',
|
||||
'atom/browser/atom_web_ui_controller_factory.cc',
|
||||
'atom/browser/atom_web_ui_controller_factory.h',
|
||||
'atom/browser/bridge_task_runner.cc',
|
||||
'atom/browser/bridge_task_runner.h',
|
||||
'atom/browser/browser.cc',
|
||||
|
@ -211,6 +213,8 @@
|
|||
'atom/browser/javascript_environment.h',
|
||||
'atom/browser/lib/bluetooth_chooser.cc',
|
||||
'atom/browser/lib/bluetooth_chooser.h',
|
||||
'atom/browser/loader/layered_resource_handler.cc',
|
||||
'atom/browser/loader/layered_resource_handler.h',
|
||||
'atom/browser/login_handler.cc',
|
||||
'atom/browser/login_handler.h',
|
||||
'atom/browser/mac/atom_application.h',
|
||||
|
@ -324,6 +328,10 @@
|
|||
'atom/browser/ui/views/submenu_button.h',
|
||||
'atom/browser/ui/views/win_frame_view.cc',
|
||||
'atom/browser/ui/views/win_frame_view.h',
|
||||
'atom/browser/ui/webui/pdf_viewer_handler.cc',
|
||||
'atom/browser/ui/webui/pdf_viewer_handler.h',
|
||||
'atom/browser/ui/webui/pdf_viewer_ui.cc',
|
||||
'atom/browser/ui/webui/pdf_viewer_ui.h',
|
||||
'atom/browser/ui/win/atom_desktop_native_widget_aura.cc',
|
||||
'atom/browser/ui/win/atom_desktop_native_widget_aura.h',
|
||||
'atom/browser/ui/win/atom_desktop_window_tree_host_win.cc',
|
||||
|
@ -605,6 +613,9 @@
|
|||
'chromium_src/chrome/renderer/tts_dispatcher.cc',
|
||||
'chromium_src/chrome/renderer/tts_dispatcher.h',
|
||||
'chromium_src/chrome/utility/utility_message_handler.h',
|
||||
'chromium_src/components/pdf/common/pdf_messages.h',
|
||||
'chromium_src/components/pdf/renderer/pepper_pdf_host.cc',
|
||||
'chromium_src/components/pdf/renderer/pepper_pdf_host.h',
|
||||
'chromium_src/extensions/browser/app_window/size_constraints.cc',
|
||||
'chromium_src/extensions/browser/app_window/size_constraints.h',
|
||||
'chromium_src/extensions/common/url_pattern.cc',
|
||||
|
@ -617,6 +628,8 @@
|
|||
'chromium_src/net/test/embedded_test_server/tcp_listen_socket.h',
|
||||
'<@(native_mate_files)',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/atom_natives.h',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/grit/pdf_viewer_resources_map.cc',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/grit/pdf_viewer_resources_map.h',
|
||||
],
|
||||
'lib_sources_linux': [
|
||||
'chromium_src/chrome/browser/icon_loader_auralinux.cc',
|
||||
|
|
|
@ -80,6 +80,9 @@ if (window.location.protocol === 'chrome-devtools:') {
|
|||
// Add implementations of chrome API.
|
||||
require('./chrome-api').injectTo(window.location.hostname, isBackgroundPage, window)
|
||||
nodeIntegration = 'false'
|
||||
} else if (window.location.protocol === 'chrome:') {
|
||||
// Disable node integration for chrome UI scheme.
|
||||
nodeIntegration = 'false'
|
||||
} else {
|
||||
// Override default web functions.
|
||||
require('./override')
|
||||
|
|
|
@ -31,6 +31,7 @@ TARGET_BINARIES = {
|
|||
'win32': [
|
||||
'{0}.exe'.format(PROJECT_NAME), # 'electron.exe'
|
||||
'content_shell.pak',
|
||||
'pdf_viewer_resources.pak',
|
||||
'd3dcompiler_47.dll',
|
||||
'icudtl.dat',
|
||||
'libEGL.dll',
|
||||
|
@ -48,6 +49,7 @@ TARGET_BINARIES = {
|
|||
'linux': [
|
||||
PROJECT_NAME, # 'electron'
|
||||
'content_shell.pak',
|
||||
'pdf_viewer_resources.pak',
|
||||
'icudtl.dat',
|
||||
'libffmpeg.so',
|
||||
'libnode.so',
|
||||
|
|
|
@ -9,7 +9,7 @@ import sys
|
|||
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
|
||||
'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent'
|
||||
LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \
|
||||
'4f5b89374df7ee69095b9f7d50b30fb46ddd7407'
|
||||
'82ea4bfcb7e594aa7b49e02c9bee32500688a62a'
|
||||
|
||||
PLATFORM = {
|
||||
'cygwin': 'win32',
|
||||
|
|
|
@ -313,11 +313,11 @@ describe('session module', function () {
|
|||
fs.unlinkSync(downloadFilePath)
|
||||
}
|
||||
|
||||
it('can download using BrowserWindow.loadURL', function (done) {
|
||||
it('can download using WebContents.downloadURL', function (done) {
|
||||
downloadServer.listen(0, '127.0.0.1', function () {
|
||||
var port = downloadServer.address().port
|
||||
ipcRenderer.sendSync('set-download-option', false, false)
|
||||
w.loadURL(url + ':' + port)
|
||||
w.webContents.downloadURL(url + ':' + port)
|
||||
ipcRenderer.once('download-done', function (event, state, url,
|
||||
mimeType, receivedBytes,
|
||||
totalBytes, disposition,
|
||||
|
@ -355,7 +355,7 @@ describe('session module', function () {
|
|||
downloadServer.listen(0, '127.0.0.1', function () {
|
||||
var port = downloadServer.address().port
|
||||
ipcRenderer.sendSync('set-download-option', true, false)
|
||||
w.loadURL(url + ':' + port + '/')
|
||||
w.webContents.downloadURL(url + ':' + port + '/')
|
||||
ipcRenderer.once('download-done', function (event, state, url,
|
||||
mimeType, receivedBytes,
|
||||
totalBytes, disposition,
|
||||
|
@ -378,7 +378,7 @@ describe('session module', function () {
|
|||
downloadServer.listen(0, '127.0.0.1', function () {
|
||||
var port = downloadServer.address().port
|
||||
ipcRenderer.sendSync('set-download-option', true, false)
|
||||
w.loadURL(url + ':' + port + '/?testFilename')
|
||||
w.webContents.downloadURL(url + ':' + port + '/?testFilename')
|
||||
ipcRenderer.once('download-done', function (event, state, url,
|
||||
mimeType, receivedBytes,
|
||||
totalBytes, disposition,
|
||||
|
|
|
@ -3,7 +3,7 @@ const http = require('http')
|
|||
const path = require('path')
|
||||
const ws = require('ws')
|
||||
const url = require('url')
|
||||
const {ipcRenderer, remote} = require('electron')
|
||||
const {ipcRenderer, remote, webFrame} = require('electron')
|
||||
const {closeWindow} = require('./window-helpers')
|
||||
|
||||
const {app, BrowserWindow, ipcMain, protocol, session, webContents} = remote
|
||||
|
@ -802,4 +802,64 @@ describe('chromium feature', function () {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('PDF Viewer', function () {
|
||||
let w = null
|
||||
const pdfSource = url.format({
|
||||
pathname: path.join(fixtures, 'assets', 'cat.pdf').replace(/\\/g, '/'),
|
||||
protocol: 'file',
|
||||
slashes: true
|
||||
})
|
||||
|
||||
beforeEach(function () {
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
preload: path.join(fixtures, 'module', 'preload-inject-ipc.js')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
return closeWindow(w).then(function () { w = null })
|
||||
})
|
||||
|
||||
it('opens when loading a pdf resource as top level navigation', function (done) {
|
||||
ipcMain.once('pdf-loaded', function (event, success) {
|
||||
if (success) done()
|
||||
})
|
||||
w.webContents.on('page-title-updated', function () {
|
||||
const source = `
|
||||
if (window.viewer) {
|
||||
window.viewer.setLoadCallback(function(success) {
|
||||
window.ipcRenderer.send('pdf-loaded', success);
|
||||
});
|
||||
}
|
||||
`
|
||||
const parsedURL = url.parse(w.webContents.getURL(), true)
|
||||
assert.equal(parsedURL.protocol, 'chrome:')
|
||||
assert.equal(parsedURL.hostname, 'pdf-viewer')
|
||||
assert.equal(parsedURL.query.src, pdfSource)
|
||||
assert.equal(w.webContents.getTitle(), 'cat.pdf')
|
||||
w.webContents.executeJavaScript(source)
|
||||
})
|
||||
w.webContents.loadURL(pdfSource)
|
||||
})
|
||||
|
||||
it('should not open when pdf is requested as sub resource', function (done) {
|
||||
webFrame.registerURLSchemeAsPrivileged('file', {
|
||||
secure: false,
|
||||
bypassCSP: false,
|
||||
allowServiceWorkers: false,
|
||||
corsEnabled: false
|
||||
})
|
||||
fetch(pdfSource).then(function (res) {
|
||||
assert.equal(res.status, 200)
|
||||
assert.notEqual(document.title, 'cat.pdf')
|
||||
done()
|
||||
}).catch(function (e) {
|
||||
done(e)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
BIN
spec/fixtures/assets/cat.pdf
vendored
Normal file
BIN
spec/fixtures/assets/cat.pdf
vendored
Normal file
Binary file not shown.
2
spec/fixtures/module/preload-inject-ipc.js
vendored
Normal file
2
spec/fixtures/module/preload-inject-ipc.js
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
const {ipcRenderer} = require('electron')
|
||||
window.ipcRenderer = ipcRenderer
|
2
vendor/brightray
vendored
2
vendor/brightray
vendored
|
@ -1 +1 @@
|
|||
Subproject commit eccdb0f1cb0fe8feaeeaf1b1a1a1cc2c3f3c7126
|
||||
Subproject commit 6ccb1aaf35248f3fff4ec63e07b110675dce9de6
|
1
vendor/pdf_viewer
vendored
Submodule
1
vendor/pdf_viewer
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit a050a339cfeabcfb5f07c313161d2ee27b6c3a39
|
Loading…
Reference in a new issue