OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/plugins/renderer/plugin_placeholder.h" | 5 #include "components/plugins/renderer/plugin_placeholder.h" |
6 | 6 |
| 7 #include "base/strings/string_util.h" |
7 #include "content/public/common/web_preferences.h" | 8 #include "content/public/common/web_preferences.h" |
8 #include "content/public/renderer/render_frame.h" | 9 #include "content/public/renderer/render_frame.h" |
| 10 #include "content/public/renderer/render_thread.h" |
| 11 #include "gin/object_template_builder.h" |
| 12 #include "third_party/WebKit/public/web/WebElement.h" |
| 13 #include "third_party/WebKit/public/web/WebPluginContainer.h" |
| 14 #include "third_party/re2/re2/re2.h" |
9 | 15 |
10 namespace plugins { | 16 namespace plugins { |
11 | 17 |
12 gin::WrapperInfo PluginPlaceholder::kWrapperInfo = {gin::kEmbedderNativeGin}; | 18 // The placeholder is loaded in normal web renderer processes, so it should not |
| 19 // have a chrome:// scheme that might let it be confused with a WebUI page. |
| 20 const char kPluginPlaceholderDataURL[] = "data:text/html,pluginplaceholderdata"; |
13 | 21 |
14 PluginPlaceholder::PluginPlaceholder(content::RenderFrame* render_frame, | 22 PluginPlaceholderBase::PluginPlaceholderBase( |
15 blink::WebLocalFrame* frame, | 23 content::RenderFrame* render_frame, |
16 const blink::WebPluginParams& params, | 24 blink::WebLocalFrame* frame, |
17 const std::string& html_data, | 25 const blink::WebPluginParams& params, |
18 GURL placeholderDataUrl) | 26 const std::string& html_data) |
19 : content::RenderFrameObserver(render_frame), | 27 : content::RenderFrameObserver(render_frame), |
20 frame_(frame), | 28 frame_(frame), |
21 plugin_params_(params), | 29 plugin_params_(params), |
22 plugin_(WebViewPlugin::Create(this, | 30 plugin_(WebViewPlugin::Create(this, |
23 render_frame | 31 render_frame |
24 ? render_frame->GetWebkitPreferences() | 32 ? render_frame->GetWebkitPreferences() |
25 : content::WebPreferences(), | 33 : content::WebPreferences(), |
26 html_data, | 34 html_data, |
27 placeholderDataUrl)) { | 35 GURL(kPluginPlaceholderDataURL))), |
28 DCHECK(placeholderDataUrl.is_valid()) | 36 hidden_(false) { |
29 << "Blink requires the placeholder to have a valid URL."; | |
30 } | 37 } |
31 | 38 |
32 PluginPlaceholder::~PluginPlaceholder() {} | 39 PluginPlaceholderBase::~PluginPlaceholderBase() { |
| 40 } |
33 | 41 |
34 const blink::WebPluginParams& PluginPlaceholder::GetPluginParams() const { | 42 const blink::WebPluginParams& PluginPlaceholderBase::GetPluginParams() const { |
35 return plugin_params_; | 43 return plugin_params_; |
36 } | 44 } |
37 | 45 |
38 void PluginPlaceholder::ShowContextMenu(const blink::WebMouseEvent& event) { | 46 void PluginPlaceholderBase::ShowContextMenu(const blink::WebMouseEvent& event) { |
39 // Does nothing by default. Will be overridden if a specific browser wants | 47 // Does nothing by default. Will be overridden if a specific browser wants |
40 // a context menu. | 48 // a context menu. |
41 return; | 49 return; |
42 } | 50 } |
43 | 51 |
44 void PluginPlaceholder::PluginDestroyed() { | 52 void PluginPlaceholderBase::PluginDestroyed() { |
45 plugin_ = NULL; | 53 plugin_ = NULL; |
46 } | 54 } |
47 | 55 |
48 v8::Local<v8::Object> PluginPlaceholder::GetV8ScriptableObject( | 56 v8::Local<v8::Object> PluginPlaceholderBase::GetV8ScriptableObject( |
49 v8::Isolate* isolate) const { | 57 v8::Isolate* isolate) const { |
50 return v8::Local<v8::Object>(); | 58 return v8::Local<v8::Object>(); |
51 } | 59 } |
52 | 60 |
53 void PluginPlaceholder::OnDestruct() { | 61 void PluginPlaceholderBase::HidePlugin() { |
| 62 hidden_ = true; |
| 63 if (!plugin()) |
| 64 return; |
| 65 blink::WebPluginContainer* container = plugin()->container(); |
| 66 blink::WebElement element = container->element(); |
| 67 element.setAttribute("style", "display: none;"); |
| 68 // If we have a width and height, search for a parent (often <div>) with the |
| 69 // same dimensions. If we find such a parent, hide that as well. |
| 70 // This makes much more uncovered page content usable (including clickable) |
| 71 // as opposed to merely visible. |
| 72 // TODO(cevans) -- it's a foul heuristic but we're going to tolerate it for |
| 73 // now for these reasons: |
| 74 // 1) Makes the user experience better. |
| 75 // 2) Foulness is encapsulated within this single function. |
| 76 // 3) Confidence in no fasle positives. |
| 77 // 4) Seems to have a good / low false negative rate at this time. |
| 78 if (element.hasAttribute("width") && element.hasAttribute("height")) { |
| 79 std::string width_str("width:[\\s]*"); |
| 80 width_str += element.getAttribute("width").utf8().data(); |
| 81 if (EndsWith(width_str, "px", false)) { |
| 82 width_str = width_str.substr(0, width_str.length() - 2); |
| 83 } |
| 84 base::TrimWhitespace(width_str, base::TRIM_TRAILING, &width_str); |
| 85 width_str += "[\\s]*px"; |
| 86 std::string height_str("height:[\\s]*"); |
| 87 height_str += element.getAttribute("height").utf8().data(); |
| 88 if (EndsWith(height_str, "px", false)) { |
| 89 height_str = height_str.substr(0, height_str.length() - 2); |
| 90 } |
| 91 base::TrimWhitespace(height_str, base::TRIM_TRAILING, &height_str); |
| 92 height_str += "[\\s]*px"; |
| 93 blink::WebNode parent = element; |
| 94 while (!parent.parentNode().isNull()) { |
| 95 parent = parent.parentNode(); |
| 96 if (!parent.isElementNode()) |
| 97 continue; |
| 98 element = parent.toConst<blink::WebElement>(); |
| 99 if (element.hasAttribute("style")) { |
| 100 std::string style_str = element.getAttribute("style").utf8(); |
| 101 if (RE2::PartialMatch(style_str, width_str) && |
| 102 RE2::PartialMatch(style_str, height_str)) |
| 103 element.setAttribute("style", "display: none;"); |
| 104 } |
| 105 } |
| 106 } |
| 107 } |
| 108 |
| 109 void PluginPlaceholderBase::HideCallback() { |
| 110 content::RenderThread::Get()->RecordAction( |
| 111 base::UserMetricsAction("Plugin_Hide_Click")); |
| 112 HidePlugin(); |
| 113 } |
| 114 |
| 115 void PluginPlaceholderBase::OnDestruct() { |
54 frame_ = NULL; | 116 frame_ = NULL; |
55 } | 117 } |
56 | 118 |
57 blink::WebLocalFrame* PluginPlaceholder::GetFrame() { return frame_; } | 119 blink::WebLocalFrame* PluginPlaceholderBase::GetFrame() { |
| 120 return frame_; |
| 121 } |
| 122 |
| 123 // static |
| 124 gin::WrapperInfo PluginPlaceholder::kWrapperInfo = {gin::kEmbedderNativeGin}; |
| 125 |
| 126 PluginPlaceholder::PluginPlaceholder(content::RenderFrame* render_frame, |
| 127 blink::WebLocalFrame* frame, |
| 128 const blink::WebPluginParams& params, |
| 129 const std::string& html_data) |
| 130 : PluginPlaceholderBase(render_frame, frame, params, html_data) { |
| 131 } |
| 132 |
| 133 PluginPlaceholder::~PluginPlaceholder() { |
| 134 } |
| 135 |
| 136 v8::Local<v8::Value> PluginPlaceholder::GetV8Handle(v8::Isolate* isolate) { |
| 137 return gin::CreateHandle(isolate, this).ToV8(); |
| 138 } |
| 139 |
| 140 gin::ObjectTemplateBuilder PluginPlaceholder::GetObjectTemplateBuilder( |
| 141 v8::Isolate* isolate) { |
| 142 return gin::Wrappable<PluginPlaceholder>::GetObjectTemplateBuilder(isolate) |
| 143 .SetMethod<void (plugins::PluginPlaceholder::*)()>( |
| 144 "hide", &PluginPlaceholder::HideCallback); |
| 145 } |
58 | 146 |
59 } // namespace plugins | 147 } // namespace plugins |
OLD | NEW |