blob: c67eaceb4cf6adb8efd78dc630f52fb2441a88d6 [file] [log] [blame]
// Copyright 2021 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 "chrome/browser/pdf/chrome_pdf_stream_delegate.h"
#include <string>
#include <utility>
#include "base/memory/weak_ptr.h"
#include "base/no_destructor.h"
#include "base/numerics/safe_conversions.h"
#include "chrome/grit/pdf_resources.h"
#include "components/pdf/browser/pdf_stream_delegate.h"
#include "content/public/browser/web_contents_user_data.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
#include "extensions/common/api/mime_handler.mojom.h"
#include "extensions/common/constants.h"
#include "printing/buildflags/buildflags.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/color_palette.h"
#include "url/gurl.h"
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
#include "chrome/common/webui_url_constants.h"
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
namespace {
// Associates a `pdf::PdfStreamDelegate::StreamInfo` with a `WebContents`.
// `ChromePdfStreamDelegate::MapToOriginalUrl()` initializes this in
// `PdfNavigationThrottle`, and then `ChromePdfStreamDelegate::GetStreamInfo()`
// returns the stashed result to `PdfURLLoaderRequestInterceptor`.
class StreamInfoHelper : public content::WebContentsUserData<StreamInfoHelper> {
public:
absl::optional<pdf::PdfStreamDelegate::StreamInfo> TakeStreamInfo() {
return std::move(stream_info_);
}
private:
friend class content::WebContentsUserData<StreamInfoHelper>;
WEB_CONTENTS_USER_DATA_KEY_DECL();
StreamInfoHelper(content::WebContents* /*contents*/,
pdf::PdfStreamDelegate::StreamInfo stream_info)
: stream_info_(std::move(stream_info)) {}
absl::optional<pdf::PdfStreamDelegate::StreamInfo> stream_info_;
};
WEB_CONTENTS_USER_DATA_KEY_IMPL(StreamInfoHelper);
} // namespace
ChromePdfStreamDelegate::ChromePdfStreamDelegate() = default;
ChromePdfStreamDelegate::~ChromePdfStreamDelegate() = default;
absl::optional<GURL> ChromePdfStreamDelegate::MapToOriginalUrl(
content::WebContents* contents,
const GURL& stream_url) {
StreamInfoHelper* helper = StreamInfoHelper::FromWebContents(contents);
if (helper) {
// PDF viewer and Print Preview only do this once per WebContents.
return absl::nullopt;
}
GURL original_url;
StreamInfo info;
extensions::MimeHandlerViewGuest* guest =
extensions::MimeHandlerViewGuest::FromWebContents(contents);
if (guest) {
base::WeakPtr<extensions::StreamContainer> stream =
guest->GetStreamWeakPtr();
if (!stream || stream->extension_id() != extension_misc::kPdfExtensionId ||
stream->stream_url() != stream_url ||
!stream->pdf_plugin_attributes()) {
return absl::nullopt;
}
original_url = stream->original_url();
info.background_color = base::checked_cast<SkColor>(
stream->pdf_plugin_attributes()->background_color);
info.full_frame = !stream->embedded();
info.allow_javascript = stream->pdf_plugin_attributes()->allow_javascript;
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
} else if (stream_url.GetWithEmptyPath() ==
chrome::kChromeUIUntrustedPrintURL) {
// Print Preview doesn't have access to `chrome.mimeHandlerPrivate`, so just
// use values that match those set by `PDFViewerPPElement`.
original_url = stream_url;
info.background_color = gfx::kGoogleGrey300;
info.full_frame = false;
info.allow_javascript = false;
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
} else {
return absl::nullopt;
}
static const base::NoDestructor<std::string> injected_script(
ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
IDR_PDF_PDF_INTERNAL_PLUGIN_WRAPPER_ROLLUP_JS));
info.stream_url = stream_url;
info.original_url = original_url;
info.injected_script = injected_script.get();
StreamInfoHelper::CreateForWebContents(contents, std::move(info));
return original_url;
}
absl::optional<pdf::PdfStreamDelegate::StreamInfo>
ChromePdfStreamDelegate::GetStreamInfo(content::WebContents* contents) {
StreamInfoHelper* helper = StreamInfoHelper::FromWebContents(contents);
if (!helper)
return absl::nullopt;
// Only the call immediately following `MapToOriginalUrl()` requires a valid
// `StreamInfo`; subsequent calls should just get nothing.
return helper->TakeStreamInfo();
}