blob: 0b62a81733c3961b7283c27c77dfd388c526e03b [file] [log] [blame]
// 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 "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
#include <utility>
#include "base/strings/stringprintf.h"
#include "components/guest_view/common/guest_view_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/host_zoom_map.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/stream_handle.h"
#include "content/public/browser/stream_info.h"
#include "content/public/common/url_constants.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_stream_manager.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_constants.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h"
#include "extensions/browser/process_manager.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/guest_view/extensions_guest_view_messages.h"
#include "extensions/strings/grit/extensions_strings.h"
#include "ipc/ipc_message_macros.h"
#include "net/base/url_util.h"
#include "services/shell/public/cpp/interface_registry.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
using content::WebContents;
using guest_view::GuestViewBase;
namespace extensions {
StreamContainer::StreamContainer(std::unique_ptr<content::StreamInfo> stream,
int tab_id,
bool embedded,
const GURL& handler_url,
const std::string& extension_id)
: stream_(std::move(stream)),
embedded_(embedded),
tab_id_(tab_id),
handler_url_(handler_url),
extension_id_(extension_id),
weak_factory_(this) {
DCHECK(stream_);
}
StreamContainer::~StreamContainer() {
}
void StreamContainer::Abort(const base::Closure& callback) {
if (!stream_->handle) {
callback.Run();
return;
}
stream_->handle->AddCloseListener(callback);
stream_->handle.reset();
}
base::WeakPtr<StreamContainer> StreamContainer::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
// static
const char MimeHandlerViewGuest::Type[] = "mimehandler";
// static
GuestViewBase* MimeHandlerViewGuest::Create(WebContents* owner_web_contents) {
return new MimeHandlerViewGuest(owner_web_contents);
}
MimeHandlerViewGuest::MimeHandlerViewGuest(WebContents* owner_web_contents)
: GuestView<MimeHandlerViewGuest>(owner_web_contents),
delegate_(ExtensionsAPIClient::Get()->CreateMimeHandlerViewGuestDelegate(
this)) {}
MimeHandlerViewGuest::~MimeHandlerViewGuest() {
}
const char* MimeHandlerViewGuest::GetAPINamespace() const {
return "mimeHandlerViewGuestInternal";
}
int MimeHandlerViewGuest::GetTaskPrefix() const {
return IDS_EXTENSION_TASK_MANAGER_MIMEHANDLERVIEW_TAG_PREFIX;
}
void MimeHandlerViewGuest::CreateWebContents(
const base::DictionaryValue& create_params,
const WebContentsCreatedCallback& callback) {
create_params.GetString(mime_handler_view::kViewId, &view_id_);
if (view_id_.empty()) {
callback.Run(nullptr);
return;
}
stream_ =
MimeHandlerStreamManager::Get(browser_context())->ReleaseStream(view_id_);
if (!stream_) {
callback.Run(nullptr);
return;
}
const Extension* mime_handler_extension =
// TODO(lazyboy): Do we need handle the case where the extension is
// terminated (ExtensionRegistry::TERMINATED)?
ExtensionRegistry::Get(browser_context())
->enabled_extensions()
.GetByID(stream_->extension_id());
if (!mime_handler_extension) {
LOG(ERROR) << "Extension for mime_type not found, mime_type = "
<< stream_->stream_info()->mime_type;
callback.Run(nullptr);
return;
}
// Use the mime handler extension's SiteInstance to create the guest so it
// goes under the same process as the extension.
ProcessManager* process_manager = ProcessManager::Get(browser_context());
scoped_refptr<content::SiteInstance> guest_site_instance =
process_manager->GetSiteInstanceForURL(stream_->handler_url());
// Clear the zoom level for the mime handler extension. The extension is
// responsible for managing its own zoom. This is necessary for OOP PDF, as
// otherwise the UI is zoomed and the calculations to determine the PDF size
// mix zoomed and unzoomed units.
content::HostZoomMap::Get(guest_site_instance.get())
->SetZoomLevelForHostAndScheme(kExtensionScheme, stream_->extension_id(),
0);
WebContents::CreateParams params(browser_context(),
guest_site_instance.get());
params.guest_delegate = this;
callback.Run(WebContents::Create(params));
}
void MimeHandlerViewGuest::DidAttachToEmbedder() {
web_contents()->GetController().LoadURL(
stream_->handler_url(), content::Referrer(),
ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
web_contents()->GetMainFrame()->GetInterfaceRegistry()->AddInterface(
base::Bind(&MimeHandlerServiceImpl::Create, stream_->GetWeakPtr()));
}
void MimeHandlerViewGuest::DidInitialize(
const base::DictionaryValue& create_params) {
ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents());
}
bool MimeHandlerViewGuest::ShouldHandleFindRequestsForEmbedder() const {
return is_full_page_plugin();
}
bool MimeHandlerViewGuest::ZoomPropagatesFromEmbedderToGuest() const {
return false;
}
WebContents* MimeHandlerViewGuest::OpenURLFromTab(
WebContents* source,
const content::OpenURLParams& params) {
return embedder_web_contents()->GetDelegate()->OpenURLFromTab(
embedder_web_contents(), params);
}
void MimeHandlerViewGuest::NavigationStateChanged(
WebContents* source,
content::InvalidateTypes changed_flags) {
if (!(changed_flags & content::INVALIDATE_TYPE_TITLE))
return;
// Only consider title changes not triggered by URL changes. Otherwise, the
// URL of the mime handler will be displayed.
if (changed_flags & content::INVALIDATE_TYPE_URL)
return;
if (!is_full_page_plugin())
return;
content::NavigationEntry* last_committed_entry =
embedder_web_contents()->GetController().GetLastCommittedEntry();
if (last_committed_entry) {
embedder_web_contents()->UpdateTitleForEntry(last_committed_entry,
source->GetTitle());
embedder_web_contents()->GetDelegate()->NavigationStateChanged(
embedder_web_contents(), changed_flags);
}
}
bool MimeHandlerViewGuest::HandleContextMenu(
const content::ContextMenuParams& params) {
if (delegate_)
return delegate_->HandleContextMenu(web_contents(), params);
return false;
}
bool MimeHandlerViewGuest::PreHandleGestureEvent(
WebContents* source,
const blink::WebGestureEvent& event) {
if (event.type == blink::WebGestureEvent::GesturePinchBegin ||
event.type == blink::WebGestureEvent::GesturePinchUpdate ||
event.type == blink::WebGestureEvent::GesturePinchEnd) {
// If we're an embedded plugin we drop pinch-gestures to avoid zooming the
// guest.
return !is_full_page_plugin();
}
return false;
}
content::JavaScriptDialogManager*
MimeHandlerViewGuest::GetJavaScriptDialogManager(
WebContents* source) {
// WebContentsDelegates often service multiple WebContentses, and use the
// WebContents* parameter to tell which WebContents made the request. If we
// pass in our own pointer to the delegate call, the delegate will be asked,
// "What's the JavaScriptDialogManager of this WebContents for which you are
// not a delegate?" And it won't be able to answer that.
//
// So we pretend to be our owner WebContents, but only for the request to
// obtain the JavaScriptDialogManager. During calls to the
// JavaScriptDialogManager we will be honest about who we are.
return owner_web_contents()->GetDelegate()->GetJavaScriptDialogManager(
owner_web_contents());
}
bool MimeHandlerViewGuest::SaveFrame(const GURL& url,
const content::Referrer& referrer) {
if (!attached())
return false;
embedder_web_contents()->SaveFrame(stream_->stream_info()->original_url,
referrer);
return true;
}
void MimeHandlerViewGuest::DocumentOnLoadCompletedInMainFrame() {
// Assume the embedder WebContents is valid here.
DCHECK(embedder_web_contents());
embedder_web_contents()->Send(
new ExtensionsGuestViewMsg_MimeHandlerViewGuestOnLoadCompleted(
element_instance_id()));
}
base::WeakPtr<StreamContainer> MimeHandlerViewGuest::GetStream() const {
if (!stream_)
return base::WeakPtr<StreamContainer>();
return stream_->GetWeakPtr();
}
} // namespace extensions