Don't preload rarely seen large images
[chromium-blink-merge.git] / components / plugins / renderer / webview_plugin.cc
blob329a10c795161f273e8616ed0e89cf4ec4668c44
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.
5 #include "components/plugins/renderer/webview_plugin.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "content/public/common/web_preferences.h"
11 #include "content/public/renderer/render_view.h"
12 #include "gin/converter.h"
13 #include "skia/ext/platform_canvas.h"
14 #include "third_party/WebKit/public/platform/WebSize.h"
15 #include "third_party/WebKit/public/platform/WebURL.h"
16 #include "third_party/WebKit/public/platform/WebURLRequest.h"
17 #include "third_party/WebKit/public/platform/WebURLResponse.h"
18 #include "third_party/WebKit/public/web/WebDocument.h"
19 #include "third_party/WebKit/public/web/WebElement.h"
20 #include "third_party/WebKit/public/web/WebInputEvent.h"
21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
22 #include "third_party/WebKit/public/web/WebPluginContainer.h"
23 #include "third_party/WebKit/public/web/WebView.h"
25 using blink::WebCanvas;
26 using blink::WebCursorInfo;
27 using blink::WebDragData;
28 using blink::WebDragOperationsMask;
29 using blink::WebImage;
30 using blink::WebInputEvent;
31 using blink::WebLocalFrame;
32 using blink::WebMouseEvent;
33 using blink::WebPlugin;
34 using blink::WebPluginContainer;
35 using blink::WebPoint;
36 using blink::WebRect;
37 using blink::WebSize;
38 using blink::WebString;
39 using blink::WebURLError;
40 using blink::WebURLRequest;
41 using blink::WebURLResponse;
42 using blink::WebVector;
43 using blink::WebView;
44 using content::WebPreferences;
46 WebViewPlugin::WebViewPlugin(WebViewPlugin::Delegate* delegate,
47 const WebPreferences& preferences)
48 : delegate_(delegate),
49 container_(NULL),
50 web_view_(WebView::create(this)),
51 finished_loading_(false),
52 focused_(false) {
53 // ApplyWebPreferences before making a WebLocalFrame so that the frame sees a
54 // consistent view of our preferences.
55 content::RenderView::ApplyWebPreferences(preferences, web_view_);
56 web_frame_ = WebLocalFrame::create(blink::WebTreeScopeType::Document, this);
57 web_view_->setMainFrame(web_frame_);
60 // static
61 WebViewPlugin* WebViewPlugin::Create(WebViewPlugin::Delegate* delegate,
62 const WebPreferences& preferences,
63 const std::string& html_data,
64 const GURL& url) {
65 DCHECK(url.is_valid()) << "Blink requires the WebView to have a valid URL.";
66 WebViewPlugin* plugin = new WebViewPlugin(delegate, preferences);
67 plugin->web_view()->mainFrame()->loadHTMLString(html_data, url);
68 return plugin;
71 WebViewPlugin::~WebViewPlugin() {
72 web_view_->close();
73 web_frame_->close();
76 void WebViewPlugin::ReplayReceivedData(WebPlugin* plugin) {
77 if (!response_.isNull()) {
78 plugin->didReceiveResponse(response_);
79 size_t total_bytes = 0;
80 for (std::list<std::string>::iterator it = data_.begin(); it != data_.end();
81 ++it) {
82 plugin->didReceiveData(
83 it->c_str(), base::checked_cast<int, size_t>(it->length()));
84 total_bytes += it->length();
86 UMA_HISTOGRAM_MEMORY_KB(
87 "PluginDocument.Memory",
88 (base::checked_cast<int, size_t>(total_bytes / 1024)));
89 UMA_HISTOGRAM_COUNTS(
90 "PluginDocument.NumChunks",
91 (base::checked_cast<int, size_t>(data_.size())));
93 // We need to transfer the |focused_| to new plugin after it loaded.
94 if (focused_) {
95 plugin->updateFocus(true, blink::WebFocusTypeNone);
97 if (finished_loading_) {
98 plugin->didFinishLoading();
100 if (error_) {
101 plugin->didFailLoading(*error_);
105 void WebViewPlugin::RestoreTitleText() {
106 if (container_)
107 container_->element().setAttribute("title", old_title_);
110 WebPluginContainer* WebViewPlugin::container() const { return container_; }
112 bool WebViewPlugin::initialize(WebPluginContainer* container) {
113 container_ = container;
114 if (container_) {
115 old_title_ = container_->element().getAttribute("title");
117 // Propagate device scale to inner webview to load the correct resource
118 // when images have a "srcset" attribute.
119 web_view_->setDeviceScaleFactor(container_->deviceScaleFactor());
121 return true;
124 void WebViewPlugin::destroy() {
125 if (delegate_) {
126 delegate_->PluginDestroyed();
127 delegate_ = NULL;
129 container_ = NULL;
130 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
133 v8::Local<v8::Object> WebViewPlugin::v8ScriptableObject(v8::Isolate* isolate) {
134 if (!delegate_)
135 return v8::Local<v8::Object>();
137 return delegate_->GetV8ScriptableObject(isolate);
140 void WebViewPlugin::layoutIfNeeded() {
141 web_view_->layout();
144 void WebViewPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
145 gfx::Rect paint_rect = gfx::IntersectRects(rect_, rect);
146 if (paint_rect.IsEmpty())
147 return;
149 paint_rect.Offset(-rect_.x(), -rect_.y());
151 canvas->save();
152 canvas->translate(SkIntToScalar(rect_.x()), SkIntToScalar(rect_.y()));
154 // Apply inverse device scale factor, as the outer webview has already
155 // applied it, and the inner webview will apply it again.
156 SkScalar inverse_scale =
157 SkFloatToScalar(1.0 / container_->deviceScaleFactor());
158 canvas->scale(inverse_scale, inverse_scale);
160 web_view_->paint(canvas, paint_rect);
162 canvas->restore();
165 // Coordinates are relative to the containing window.
166 void WebViewPlugin::updateGeometry(const WebRect& window_rect,
167 const WebRect& clip_rect,
168 const WebRect& unobscured_rect,
169 const WebVector<WebRect>& cut_outs_rects,
170 bool is_visible) {
171 if (static_cast<gfx::Rect>(window_rect) != rect_) {
172 rect_ = window_rect;
173 WebSize newSize(window_rect.width, window_rect.height);
174 web_view_->resize(newSize);
177 if (delegate_)
178 delegate_->OnUnobscuredSizeUpdate(gfx::Rect(unobscured_rect).size());
181 void WebViewPlugin::updateFocus(bool focused, blink::WebFocusType focus_type) {
182 focused_ = focused;
185 bool WebViewPlugin::acceptsInputEvents() { return true; }
187 bool WebViewPlugin::handleInputEvent(const WebInputEvent& event,
188 WebCursorInfo& cursor) {
189 // For tap events, don't handle them. They will be converted to
190 // mouse events later and passed to here.
191 if (event.type == WebInputEvent::GestureTap)
192 return false;
194 // For LongPress events we return false, since otherwise the context menu will
195 // be suppressed. https://crbug.com/482842
196 if (event.type == WebInputEvent::GestureLongPress)
197 return false;
199 if (event.type == WebInputEvent::ContextMenu) {
200 if (delegate_) {
201 const WebMouseEvent& mouse_event =
202 reinterpret_cast<const WebMouseEvent&>(event);
203 delegate_->ShowContextMenu(mouse_event);
205 return true;
207 current_cursor_ = cursor;
208 bool handled = web_view_->handleInputEvent(event);
209 cursor = current_cursor_;
211 return handled;
214 void WebViewPlugin::didReceiveResponse(const WebURLResponse& response) {
215 DCHECK(response_.isNull());
216 response_ = response;
219 void WebViewPlugin::didReceiveData(const char* data, int data_length) {
220 data_.push_back(std::string(data, data_length));
223 void WebViewPlugin::didFinishLoading() {
224 DCHECK(!finished_loading_);
225 finished_loading_ = true;
228 void WebViewPlugin::didFailLoading(const WebURLError& error) {
229 DCHECK(!error_.get());
230 error_.reset(new WebURLError(error));
233 bool WebViewPlugin::acceptsLoadDrops() { return false; }
235 void WebViewPlugin::setToolTipText(const WebString& text,
236 blink::WebTextDirection hint) {
237 if (container_)
238 container_->element().setAttribute("title", text);
241 void WebViewPlugin::startDragging(WebLocalFrame*,
242 const WebDragData&,
243 WebDragOperationsMask,
244 const WebImage&,
245 const WebPoint&) {
246 // Immediately stop dragging.
247 web_view_->dragSourceSystemDragEnded();
250 bool WebViewPlugin::allowsBrokenNullLayerTreeView() const {
251 return true;
254 void WebViewPlugin::didInvalidateRect(const WebRect& rect) {
255 if (container_)
256 container_->invalidateRect(rect);
259 void WebViewPlugin::didChangeCursor(const WebCursorInfo& cursor) {
260 current_cursor_ = cursor;
263 void WebViewPlugin::scheduleAnimation() {
264 if (container_)
265 container_->setNeedsLayout();
268 void WebViewPlugin::didClearWindowObject(WebLocalFrame* frame) {
269 if (!delegate_)
270 return;
272 v8::Isolate* isolate = blink::mainThreadIsolate();
273 v8::HandleScope handle_scope(isolate);
274 v8::Local<v8::Context> context = frame->mainWorldScriptContext();
275 DCHECK(!context.IsEmpty());
277 v8::Context::Scope context_scope(context);
278 v8::Local<v8::Object> global = context->Global();
280 global->Set(gin::StringToV8(isolate, "plugin"),
281 delegate_->GetV8Handle(isolate));
284 void WebViewPlugin::didReceiveResponse(WebLocalFrame* frame,
285 unsigned identifier,
286 const WebURLResponse& response) {
287 WebFrameClient::didReceiveResponse(frame, identifier, response);