blob: 1a6d1f262e1981dfe8e8ef845a24f354ffc736a9 [file] [log] [blame]
// Copyright 2020 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 "pdf/pdf_view_web_plugin.h"
#include <stddef.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/check_op.h"
#include "base/location.h"
#include "base/notreached.h"
#include "base/thread_annotations.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "cc/paint/paint_canvas.h"
#include "net/cookies/site_for_cookies.h"
#include "pdf/pdf_engine.h"
#include "pdf/pdf_init.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "pdf/ppapi_migration/graphics.h"
#include "pdf/ppapi_migration/url_loader.h"
#include "ppapi/c/pp_errors.h"
#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
#include "third_party/blink/public/common/metrics/document_update_reason.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-shared.h"
#include "third_party/blink/public/platform/web_input_event_result.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_error.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/public/web/web_associated_url_loader.h"
#include "third_party/blink/public/web/web_associated_url_loader_options.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_plugin_container.h"
#include "third_party/blink/public/web/web_plugin_params.h"
#include "ui/base/cursor/cursor.h"
namespace chrome_pdf {
namespace {
// Initialization performed per renderer process. Initialization may be
// triggered from multiple plugin instances, but should only execute once.
//
// TODO(crbug.com/1123621): We may be able to simplify this once we've figured
// out exactly which processes need to initialize and shutdown PDFium.
class PerProcessInitializer final {
public:
static PerProcessInitializer& GetInstance() {
static PerProcessInitializer instance;
return instance;
}
void Acquire() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_GE(init_count_, 0);
if (init_count_++ > 0)
return;
DCHECK(!IsSDKInitializedViaPlugin());
// TODO(crbug.com/1111024): Support JavaScript.
InitializeSDK(/*enable_v8=*/false);
SetIsSDKInitializedViaPlugin(true);
}
void Release() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_GT(init_count_, 0);
if (--init_count_ > 0)
return;
DCHECK(IsSDKInitializedViaPlugin());
ShutdownSDK();
SetIsSDKInitializedViaPlugin(false);
}
private:
int init_count_ GUARDED_BY_CONTEXT(thread_checker_) = 0;
// TODO(crbug.com/1123731): Assuming PDFium is thread-hostile for now, and
// must use one thread exclusively.
THREAD_CHECKER(thread_checker_);
};
} // namespace
PdfViewWebPlugin::PdfViewWebPlugin(const blink::WebPluginParams& params)
: initial_params_(params) {}
PdfViewWebPlugin::~PdfViewWebPlugin() = default;
// Modeled on `OutOfProcessInstance::Init()`.
bool PdfViewWebPlugin::Initialize(blink::WebPluginContainer* container) {
DCHECK_EQ(container->Plugin(), this);
container_ = container;
std::string stream_url;
for (size_t i = 0; i < initial_params_.attribute_names.size(); ++i) {
if (initial_params_.attribute_names[i] == "stream-url") {
stream_url = initial_params_.attribute_values[i].Utf8();
} else if (initial_params_.attribute_names[i] == "background-color") {
uint32_t background_color;
if (!base::HexStringToUInt(initial_params_.attribute_values[i].Utf8(),
&background_color)) {
return false;
}
SetBackgroundColor(background_color);
} else if (initial_params_.attribute_names[i] == "top-toolbar-height") {
int toolbar_height;
if (!base::StringToInt(initial_params_.attribute_values[i].Utf8(),
&toolbar_height)) {
return false;
}
set_top_toolbar_height_in_viewport_coords(toolbar_height);
}
}
// Contents of `initial_params_` no longer needed.
initial_params_ = {};
PerProcessInitializer::GetInstance().Acquire();
InitializeEngine(PDFiumFormFiller::ScriptOption::kNoJavaScript);
LoadUrl(stream_url, /*is_print_preview=*/false);
return true;
}
void PdfViewWebPlugin::Destroy() {
if (container_) {
// Explicitly destroy the PDFEngine during destruction as it may call back
// into this object.
DestroyEngine();
PerProcessInitializer::GetInstance().Release();
}
container_ = nullptr;
delete this;
}
blink::WebPluginContainer* PdfViewWebPlugin::Container() const {
return container_;
}
void PdfViewWebPlugin::UpdateAllLifecyclePhases(
blink::DocumentUpdateReason reason) {}
void PdfViewWebPlugin::Paint(cc::PaintCanvas* canvas, const gfx::Rect& rect) {}
void PdfViewWebPlugin::UpdateGeometry(const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
const gfx::Rect& unobscured_rect,
bool is_visible) {}
void PdfViewWebPlugin::UpdateFocus(bool focused,
blink::mojom::FocusType focus_type) {}
void PdfViewWebPlugin::UpdateVisibility(bool visibility) {}
blink::WebInputEventResult PdfViewWebPlugin::HandleInputEvent(
const blink::WebCoalescedInputEvent& event,
ui::Cursor* cursor) {
return blink::WebInputEventResult::kNotHandled;
}
void PdfViewWebPlugin::DidReceiveResponse(
const blink::WebURLResponse& response) {}
void PdfViewWebPlugin::DidReceiveData(const char* data, size_t data_length) {}
void PdfViewWebPlugin::DidFinishLoading() {}
void PdfViewWebPlugin::DidFailLoading(const blink::WebURLError& error) {}
void PdfViewWebPlugin::ProposeDocumentLayout(const DocumentLayout& layout) {}
void PdfViewWebPlugin::Invalidate(const gfx::Rect& rect) {}
void PdfViewWebPlugin::DidScroll(const gfx::Vector2d& offset) {}
void PdfViewWebPlugin::ScrollToX(int x_in_screen_coords) {}
void PdfViewWebPlugin::ScrollToY(int y_in_screen_coords,
bool compensate_for_toolbar) {}
void PdfViewWebPlugin::ScrollBy(const gfx::Vector2d& scroll_delta) {}
void PdfViewWebPlugin::ScrollToPage(int page) {}
void PdfViewWebPlugin::NavigateTo(const std::string& url,
WindowOpenDisposition disposition) {}
void PdfViewWebPlugin::NavigateToDestination(int page,
const float* x,
const float* y,
const float* zoom) {}
void PdfViewWebPlugin::UpdateCursor(PP_CursorType_Dev cursor) {}
void PdfViewWebPlugin::UpdateTickMarks(
const std::vector<gfx::Rect>& tickmarks) {}
void PdfViewWebPlugin::NotifyNumberOfFindResultsChanged(int total,
bool final_result) {}
void PdfViewWebPlugin::NotifySelectedFindResultChanged(int current_find_index) {
}
void PdfViewWebPlugin::NotifyTouchSelectionOccurred() {}
void PdfViewWebPlugin::GetDocumentPassword(
base::OnceCallback<void(const std::string&)> callback) {}
void PdfViewWebPlugin::Beep() {}
void PdfViewWebPlugin::Alert(const std::string& message) {}
bool PdfViewWebPlugin::Confirm(const std::string& message) {
return false;
}
std::string PdfViewWebPlugin::Prompt(const std::string& question,
const std::string& default_answer) {
return "";
}
std::string PdfViewWebPlugin::GetURL() {
return "";
}
void PdfViewWebPlugin::Email(const std::string& to,
const std::string& cc,
const std::string& bcc,
const std::string& subject,
const std::string& body) {}
void PdfViewWebPlugin::Print() {}
void PdfViewWebPlugin::SubmitForm(const std::string& url,
const void* data,
int length) {}
std::unique_ptr<UrlLoader> PdfViewWebPlugin::CreateUrlLoader() {
return nullptr;
}
std::vector<PDFEngine::Client::SearchStringResult>
PdfViewWebPlugin::SearchString(const base::char16* string,
const base::char16* term,
bool case_sensitive) {
return {};
}
void PdfViewWebPlugin::DocumentLoadComplete(
const PDFEngine::DocumentFeatures& document_features) {
NOTIMPLEMENTED();
}
void PdfViewWebPlugin::DocumentLoadFailed() {
NOTIMPLEMENTED();
}
pp::Instance* PdfViewWebPlugin::GetPluginInstance() {
return nullptr;
}
void PdfViewWebPlugin::DocumentHasUnsupportedFeature(
const std::string& feature) {}
void PdfViewWebPlugin::DocumentLoadProgress(uint32_t available,
uint32_t doc_size) {}
void PdfViewWebPlugin::FormTextFieldFocusChange(bool in_focus) {}
bool PdfViewWebPlugin::IsPrintPreview() {
return false;
}
void PdfViewWebPlugin::IsSelectingChanged(bool is_selecting) {}
void PdfViewWebPlugin::SelectionChanged(const gfx::Rect& left,
const gfx::Rect& right) {}
void PdfViewWebPlugin::EnteredEditMode() {}
float PdfViewWebPlugin::GetToolbarHeightInScreenCoords() {
return 0;
}
void PdfViewWebPlugin::DocumentFocusChanged(bool document_has_focus) {}
void PdfViewWebPlugin::SetSelectedText(const std::string& selected_text) {
NOTIMPLEMENTED();
}
void PdfViewWebPlugin::SetLinkUnderCursor(
const std::string& link_under_cursor) {
NOTIMPLEMENTED();
}
bool PdfViewWebPlugin::IsValidLink(const std::string& url) {
return base::Value(url).is_string();
}
std::unique_ptr<Graphics> PdfViewWebPlugin::CreatePaintGraphics(
const gfx::Size& size) {
auto graphics = SkiaGraphics::Create(size);
DCHECK(graphics);
return graphics;
}
bool PdfViewWebPlugin::BindPaintGraphics(Graphics& graphics) {
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
void PdfViewWebPlugin::ScheduleTaskOnMainThread(
base::TimeDelta delay,
ResultCallback callback,
int32_t result,
const base::Location& from_here) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
from_here, base::BindOnce(std::move(callback), result), delay);
}
bool PdfViewWebPlugin::IsValid() const {
return container_ && container_->GetDocument().GetFrame();
}
blink::WebURL PdfViewWebPlugin::CompleteURL(
const blink::WebString& partial_url) const {
DCHECK(IsValid());
return container_->GetDocument().CompleteURL(partial_url);
}
net::SiteForCookies PdfViewWebPlugin::SiteForCookies() const {
DCHECK(IsValid());
return container_->GetDocument().SiteForCookies();
}
void PdfViewWebPlugin::SetReferrerForRequest(
blink::WebURLRequest& request,
const blink::WebURL& referrer_url) {
DCHECK(IsValid());
container_->GetDocument().GetFrame()->SetReferrerForRequest(request,
referrer_url);
}
std::unique_ptr<blink::WebAssociatedURLLoader>
PdfViewWebPlugin::CreateAssociatedURLLoader(
const blink::WebAssociatedURLLoaderOptions& options) {
DCHECK(IsValid());
return container_->GetDocument().GetFrame()->CreateAssociatedURLLoader(
options);
}
base::WeakPtr<PdfViewPluginBase> PdfViewWebPlugin::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
std::unique_ptr<UrlLoader> PdfViewWebPlugin::CreateUrlLoaderInternal() {
auto loader = std::make_unique<BlinkUrlLoader>(weak_factory_.GetWeakPtr());
loader->GrantUniversalAccess();
return loader;
}
// Modeled on `OutOfProcessInstance::DidOpen()`.
void PdfViewWebPlugin::DidOpen(std::unique_ptr<UrlLoader> loader,
int32_t result) {
if (result == PP_OK) {
if (!engine()->HandleDocumentLoad(std::move(loader)))
DocumentLoadFailed();
} else {
NOTIMPLEMENTED();
}
}
void PdfViewWebPlugin::DidOpenPreview(std::unique_ptr<UrlLoader> loader,
int32_t result) {
NOTIMPLEMENTED();
}
// TODO(https://crbug.com/1099020): To be implemented as a Pepper-free version
// of `OutOfProcessInstance::DoPaint()`
void PdfViewWebPlugin::DoPaint(const std::vector<gfx::Rect>& paint_rects,
std::vector<PaintReadyRect>* ready,
std::vector<gfx::Rect>* pending) {
NOTIMPLEMENTED_LOG_ONCE();
}
void PdfViewWebPlugin::OnGeometryChanged(double old_zoom,
float old_device_scale) {
RecalculateAreas(old_zoom, old_device_scale);
// TODO(https://crbug.com/1144444): Add a Pepper-free implementation to update
// accessibility information in the viewport.
}
} // namespace chrome_pdf