webview_plugin.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "components/plugins/renderer/webview_plugin.h" 6 7#include "base/message_loop/message_loop.h" 8#include "base/metrics/histogram.h" 9#include "base/numerics/safe_conversions.h" 10#include "content/public/renderer/web_preferences.h" 11#include "skia/ext/platform_canvas.h" 12#include "third_party/WebKit/public/platform/WebSize.h" 13#include "third_party/WebKit/public/platform/WebURL.h" 14#include "third_party/WebKit/public/platform/WebURLRequest.h" 15#include "third_party/WebKit/public/platform/WebURLResponse.h" 16#include "third_party/WebKit/public/web/WebDocument.h" 17#include "third_party/WebKit/public/web/WebElement.h" 18#include "third_party/WebKit/public/web/WebInputEvent.h" 19#include "third_party/WebKit/public/web/WebLocalFrame.h" 20#include "third_party/WebKit/public/web/WebPluginContainer.h" 21#include "third_party/WebKit/public/web/WebView.h" 22#include "webkit/common/webpreferences.h" 23 24using blink::WebCanvas; 25using blink::WebCursorInfo; 26using blink::WebDragData; 27using blink::WebDragOperationsMask; 28using blink::WebImage; 29using blink::WebInputEvent; 30using blink::WebLocalFrame; 31using blink::WebMouseEvent; 32using blink::WebPlugin; 33using blink::WebPluginContainer; 34using blink::WebPoint; 35using blink::WebRect; 36using blink::WebSize; 37using blink::WebString; 38using blink::WebURLError; 39using blink::WebURLRequest; 40using blink::WebURLResponse; 41using blink::WebVector; 42using blink::WebView; 43 44WebViewPlugin::WebViewPlugin(WebViewPlugin::Delegate* delegate) 45 : delegate_(delegate), 46 container_(NULL), 47 web_view_(WebView::create(this)), 48 web_frame_(WebLocalFrame::create(this)), 49 finished_loading_(false), 50 focused_(false) { 51 web_view_->setMainFrame(web_frame_); 52} 53 54// static 55WebViewPlugin* WebViewPlugin::Create(WebViewPlugin::Delegate* delegate, 56 const WebPreferences& preferences, 57 const std::string& html_data, 58 const GURL& url) { 59 WebViewPlugin* plugin = new WebViewPlugin(delegate); 60 WebView* web_view = plugin->web_view(); 61 content::ApplyWebPreferences(preferences, web_view); 62 web_view->mainFrame()->loadHTMLString(html_data, url); 63 return plugin; 64} 65 66WebViewPlugin::~WebViewPlugin() { 67 web_view_->close(); 68 web_frame_->close(); 69} 70 71void WebViewPlugin::ReplayReceivedData(WebPlugin* plugin) { 72 if (!response_.isNull()) { 73 plugin->didReceiveResponse(response_); 74 size_t total_bytes = 0; 75 for (std::list<std::string>::iterator it = data_.begin(); it != data_.end(); 76 ++it) { 77 plugin->didReceiveData( 78 it->c_str(), base::checked_cast<int, size_t>(it->length())); 79 total_bytes += it->length(); 80 } 81 UMA_HISTOGRAM_MEMORY_KB( 82 "PluginDocument.Memory", 83 (base::checked_cast<int, size_t>(total_bytes / 1024))); 84 UMA_HISTOGRAM_COUNTS( 85 "PluginDocument.NumChunks", 86 (base::checked_cast<int, size_t>(data_.size()))); 87 } 88 // We need to transfer the |focused_| to new plugin after it loaded. 89 if (focused_) { 90 plugin->updateFocus(true); 91 } 92 if (finished_loading_) { 93 plugin->didFinishLoading(); 94 } 95 if (error_) { 96 plugin->didFailLoading(*error_); 97 } 98} 99 100void WebViewPlugin::RestoreTitleText() { 101 if (container_) 102 container_->element().setAttribute("title", old_title_); 103} 104 105WebPluginContainer* WebViewPlugin::container() const { return container_; } 106 107bool WebViewPlugin::initialize(WebPluginContainer* container) { 108 container_ = container; 109 if (container_) 110 old_title_ = container_->element().getAttribute("title"); 111 return true; 112} 113 114void WebViewPlugin::destroy() { 115 if (delegate_) { 116 delegate_->PluginDestroyed(); 117 delegate_ = NULL; 118 } 119 container_ = NULL; 120 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 121} 122 123NPObject* WebViewPlugin::scriptableObject() { return NULL; } 124 125struct _NPP* WebViewPlugin::pluginNPP() { return NULL; } 126 127bool WebViewPlugin::getFormValue(WebString& value) { return false; } 128 129void WebViewPlugin::paint(WebCanvas* canvas, const WebRect& rect) { 130 gfx::Rect paint_rect = gfx::IntersectRects(rect_, rect); 131 if (paint_rect.IsEmpty()) 132 return; 133 134 paint_rect.Offset(-rect_.x(), -rect_.y()); 135 136 canvas->translate(SkIntToScalar(rect_.x()), SkIntToScalar(rect_.y())); 137 canvas->save(); 138 139 web_view_->layout(); 140 web_view_->paint(canvas, paint_rect); 141 142 canvas->restore(); 143} 144 145// Coordinates are relative to the containing window. 146void WebViewPlugin::updateGeometry(const WebRect& frame_rect, 147 const WebRect& clip_rect, 148 const WebVector<WebRect>& cut_out_rects, 149 bool is_visible) { 150 if (static_cast<gfx::Rect>(frame_rect) != rect_) { 151 rect_ = frame_rect; 152 WebSize newSize(frame_rect.width, frame_rect.height); 153 web_view_->setFixedLayoutSize(newSize); 154 web_view_->resize(newSize); 155 } 156} 157 158void WebViewPlugin::updateFocus(bool focused) { 159 focused_ = focused; 160} 161 162bool WebViewPlugin::acceptsInputEvents() { return true; } 163 164bool WebViewPlugin::handleInputEvent(const WebInputEvent& event, 165 WebCursorInfo& cursor) { 166 // For tap events, don't handle them. They will be converted to 167 // mouse events later and passed to here. 168 if (event.type == WebInputEvent::GestureTap) 169 return false; 170 171 if (event.type == WebInputEvent::ContextMenu) { 172 if (delegate_) { 173 const WebMouseEvent& mouse_event = 174 reinterpret_cast<const WebMouseEvent&>(event); 175 delegate_->ShowContextMenu(mouse_event); 176 } 177 return true; 178 } 179 current_cursor_ = cursor; 180 bool handled = web_view_->handleInputEvent(event); 181 cursor = current_cursor_; 182 183 return handled; 184} 185 186void WebViewPlugin::didReceiveResponse(const WebURLResponse& response) { 187 DCHECK(response_.isNull()); 188 response_ = response; 189} 190 191void WebViewPlugin::didReceiveData(const char* data, int data_length) { 192 data_.push_back(std::string(data, data_length)); 193} 194 195void WebViewPlugin::didFinishLoading() { 196 DCHECK(!finished_loading_); 197 finished_loading_ = true; 198} 199 200void WebViewPlugin::didFailLoading(const WebURLError& error) { 201 DCHECK(!error_.get()); 202 error_.reset(new WebURLError(error)); 203} 204 205bool WebViewPlugin::acceptsLoadDrops() { return false; } 206 207void WebViewPlugin::setToolTipText(const WebString& text, 208 blink::WebTextDirection hint) { 209 if (container_) 210 container_->element().setAttribute("title", text); 211} 212 213void WebViewPlugin::startDragging(WebLocalFrame*, 214 const WebDragData&, 215 WebDragOperationsMask, 216 const WebImage&, 217 const WebPoint&) { 218 // Immediately stop dragging. 219 web_view_->dragSourceSystemDragEnded(); 220} 221 222void WebViewPlugin::didInvalidateRect(const WebRect& rect) { 223 if (container_) 224 container_->invalidateRect(rect); 225} 226 227void WebViewPlugin::didChangeCursor(const WebCursorInfo& cursor) { 228 current_cursor_ = cursor; 229} 230 231void WebViewPlugin::didClearWindowObject(WebLocalFrame* frame, int world_id) { 232 if (delegate_) 233 delegate_->BindWebFrame(frame); 234} 235 236void WebViewPlugin::didReceiveResponse(WebLocalFrame* frame, 237 unsigned identifier, 238 const WebURLResponse& response) { 239 WebFrameClient::didReceiveResponse(frame, identifier, response); 240} 241