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