1// Copyright (c) 2011 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/browser/tab_contents/render_view_host_delegate_helper.h"
6
7#include <string>
8
9#include "base/command_line.h"
10#include "base/string_util.h"
11#include "base/utf_string_conversions.h"
12#include "chrome/browser/background_contents_service.h"
13#include "chrome/browser/background_contents_service_factory.h"
14#include "chrome/browser/character_encoding.h"
15#include "chrome/browser/extensions/extension_service.h"
16#include "chrome/browser/gpu_data_manager.h"
17#include "chrome/browser/prefs/pref_service.h"
18#include "chrome/browser/prefs/scoped_user_pref_update.h"
19#include "chrome/browser/profiles/profile.h"
20#include "chrome/browser/tab_contents/background_contents.h"
21#include "chrome/browser/user_style_sheet_watcher.h"
22#include "chrome/common/chrome_switches.h"
23#include "chrome/common/pref_names.h"
24#include "content/browser/renderer_host/render_view_host.h"
25#include "content/browser/renderer_host/render_process_host.h"
26#include "content/browser/renderer_host/render_widget_fullscreen_host.h"
27#include "content/browser/renderer_host/render_widget_host.h"
28#include "content/browser/renderer_host/render_widget_host_view.h"
29#include "content/browser/site_instance.h"
30#include "content/browser/tab_contents/tab_contents.h"
31#include "content/browser/tab_contents/tab_contents_view.h"
32#include "content/browser/webui/web_ui.h"
33
34RenderViewHostDelegateViewHelper::RenderViewHostDelegateViewHelper() {}
35
36RenderViewHostDelegateViewHelper::~RenderViewHostDelegateViewHelper() {}
37
38BackgroundContents*
39RenderViewHostDelegateViewHelper::MaybeCreateBackgroundContents(
40    int route_id,
41    Profile* profile,
42    SiteInstance* site,
43    const GURL& opener_url,
44    const string16& frame_name) {
45  ExtensionService* extensions_service = profile->GetExtensionService();
46
47  if (!opener_url.is_valid() ||
48      frame_name.empty() ||
49      !extensions_service ||
50      !extensions_service->is_ready())
51    return NULL;
52
53  // Only hosted apps have web extents, so this ensures that only hosted apps
54  // can create BackgroundContents. We don't have to check for background
55  // permission as that is checked in RenderMessageFilter when the CreateWindow
56  // message is processed.
57  const Extension* extension =
58      extensions_service->GetExtensionByWebExtent(opener_url);
59  if (!extension)
60    return NULL;
61
62  // If the extension manifest specifies a background page, then don't allow one
63  // to be created here.
64  if (extension->background_url().is_valid())
65    return NULL;
66
67  // Only allow a single background contents per app.
68  BackgroundContentsService* service =
69      BackgroundContentsServiceFactory::GetForProfile(profile);
70  if (!service || service->GetAppBackgroundContents(
71          ASCIIToUTF16(extension->id())))
72    return NULL;
73
74  // Ensure that we're trying to open this from the extension's process.
75  ExtensionProcessManager* process_manager =
76      profile->GetExtensionProcessManager();
77  if (!site->GetProcess() || !process_manager ||
78      site->GetProcess() != process_manager->GetExtensionProcess(opener_url))
79    return NULL;
80
81  // Passed all the checks, so this should be created as a BackgroundContents.
82  return service->CreateBackgroundContents(site, route_id, profile, frame_name,
83                                           ASCIIToUTF16(extension->id()));
84}
85
86TabContents* RenderViewHostDelegateViewHelper::CreateNewWindow(
87    int route_id,
88    Profile* profile,
89    SiteInstance* site,
90    WebUI::TypeID webui_type,
91    RenderViewHostDelegate* opener,
92    WindowContainerType window_container_type,
93    const string16& frame_name) {
94  if (window_container_type == WINDOW_CONTAINER_TYPE_BACKGROUND) {
95    BackgroundContents* contents = MaybeCreateBackgroundContents(
96        route_id,
97        profile,
98        site,
99        opener->GetURL(),
100        frame_name);
101    if (contents) {
102      pending_contents_[route_id] = contents->render_view_host();
103      return NULL;
104    }
105  }
106
107  // Create the new web contents. This will automatically create the new
108  // TabContentsView. In the future, we may want to create the view separately.
109  TabContents* new_contents =
110      new TabContents(profile,
111                      site,
112                      route_id,
113                      opener->GetAsTabContents(),
114                      NULL);
115  new_contents->set_opener_web_ui_type(webui_type);
116  TabContentsView* new_view = new_contents->view();
117
118  // TODO(brettw) it seems bogus that we have to call this function on the
119  // newly created object and give it one of its own member variables.
120  new_view->CreateViewForWidget(new_contents->render_view_host());
121
122  // Save the created window associated with the route so we can show it later.
123  pending_contents_[route_id] = new_contents->render_view_host();
124  return new_contents;
125}
126
127RenderWidgetHostView* RenderViewHostDelegateViewHelper::CreateNewWidget(
128    int route_id, WebKit::WebPopupType popup_type, RenderProcessHost* process) {
129  RenderWidgetHost* widget_host =
130      new RenderWidgetHost(process, route_id);
131  RenderWidgetHostView* widget_view =
132      RenderWidgetHostView::CreateViewForWidget(widget_host);
133  // Popups should not get activated.
134  widget_view->set_popup_type(popup_type);
135  // Save the created widget associated with the route so we can show it later.
136  pending_widget_views_[route_id] = widget_view;
137  return widget_view;
138}
139
140RenderWidgetHostView*
141RenderViewHostDelegateViewHelper::CreateNewFullscreenWidget(
142    int route_id, RenderProcessHost* process) {
143  RenderWidgetFullscreenHost* fullscreen_widget_host =
144      new RenderWidgetFullscreenHost(process, route_id);
145  RenderWidgetHostView* widget_view =
146      RenderWidgetHostView::CreateViewForWidget(fullscreen_widget_host);
147  pending_widget_views_[route_id] = widget_view;
148  return widget_view;
149}
150
151TabContents* RenderViewHostDelegateViewHelper::GetCreatedWindow(int route_id) {
152  PendingContents::iterator iter = pending_contents_.find(route_id);
153  if (iter == pending_contents_.end()) {
154    DCHECK(false);
155    return NULL;
156  }
157
158  RenderViewHost* new_rvh = iter->second;
159  pending_contents_.erase(route_id);
160
161  // The renderer crashed or it is a TabContents and has no view.
162  if (!new_rvh->process()->HasConnection() ||
163      (new_rvh->delegate()->GetAsTabContents() && !new_rvh->view()))
164    return NULL;
165
166  // TODO(brettw) this seems bogus to reach into here and initialize the host.
167  new_rvh->Init();
168  return new_rvh->delegate()->GetAsTabContents();
169}
170
171RenderWidgetHostView* RenderViewHostDelegateViewHelper::GetCreatedWidget(
172    int route_id) {
173  PendingWidgetViews::iterator iter = pending_widget_views_.find(route_id);
174  if (iter == pending_widget_views_.end()) {
175    DCHECK(false);
176    return NULL;
177  }
178
179  RenderWidgetHostView* widget_host_view = iter->second;
180  pending_widget_views_.erase(route_id);
181
182  RenderWidgetHost* widget_host = widget_host_view->GetRenderWidgetHost();
183  if (!widget_host->process()->HasConnection()) {
184    // The view has gone away or the renderer crashed. Nothing to do.
185    return NULL;
186  }
187
188  return widget_host_view;
189}
190
191void RenderViewHostDelegateViewHelper::RenderWidgetHostDestroyed(
192    RenderWidgetHost* host) {
193  for (PendingWidgetViews::iterator i = pending_widget_views_.begin();
194       i != pending_widget_views_.end(); ++i) {
195    if (host->view() == i->second) {
196      pending_widget_views_.erase(i);
197      return;
198    }
199  }
200}
201
202bool RenderViewHostDelegateHelper::gpu_enabled_ = true;
203
204// static
205WebPreferences RenderViewHostDelegateHelper::GetWebkitPrefs(
206    Profile* profile, bool is_web_ui) {
207  PrefService* prefs = profile->GetPrefs();
208  WebPreferences web_prefs;
209
210  web_prefs.standard_font_family =
211      UTF8ToUTF16(prefs->GetString(prefs::kWebKitStandardFontFamily));
212  web_prefs.fixed_font_family =
213      UTF8ToUTF16(prefs->GetString(prefs::kWebKitFixedFontFamily));
214  web_prefs.serif_font_family =
215      UTF8ToUTF16(prefs->GetString(prefs::kWebKitSerifFontFamily));
216  web_prefs.sans_serif_font_family =
217      UTF8ToUTF16(prefs->GetString(prefs::kWebKitSansSerifFontFamily));
218  web_prefs.cursive_font_family =
219      UTF8ToUTF16(prefs->GetString(prefs::kWebKitCursiveFontFamily));
220  web_prefs.fantasy_font_family =
221      UTF8ToUTF16(prefs->GetString(prefs::kWebKitFantasyFontFamily));
222
223  web_prefs.default_font_size =
224      prefs->GetInteger(prefs::kWebKitDefaultFontSize);
225  web_prefs.default_fixed_font_size =
226      prefs->GetInteger(prefs::kWebKitDefaultFixedFontSize);
227  web_prefs.minimum_font_size =
228      prefs->GetInteger(prefs::kWebKitMinimumFontSize);
229  web_prefs.minimum_logical_font_size =
230      prefs->GetInteger(prefs::kWebKitMinimumLogicalFontSize);
231
232  web_prefs.default_encoding = prefs->GetString(prefs::kDefaultCharset);
233
234  web_prefs.javascript_can_open_windows_automatically =
235      prefs->GetBoolean(prefs::kWebKitJavascriptCanOpenWindowsAutomatically);
236  web_prefs.dom_paste_enabled =
237      prefs->GetBoolean(prefs::kWebKitDomPasteEnabled);
238  web_prefs.shrinks_standalone_images_to_fit =
239      prefs->GetBoolean(prefs::kWebKitShrinksStandaloneImagesToFit);
240  const DictionaryValue* inspector_settings =
241      prefs->GetDictionary(prefs::kWebKitInspectorSettings);
242  if (inspector_settings) {
243    for (DictionaryValue::key_iterator iter(inspector_settings->begin_keys());
244         iter != inspector_settings->end_keys(); ++iter) {
245      std::string value;
246      if (inspector_settings->GetStringWithoutPathExpansion(*iter, &value))
247          web_prefs.inspector_settings.push_back(
248              std::make_pair(*iter, value));
249    }
250  }
251  web_prefs.tabs_to_links = prefs->GetBoolean(prefs::kWebkitTabsToLinks);
252
253  {  // Command line switches are used for preferences with no user interface.
254    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
255    web_prefs.developer_extras_enabled =
256        !command_line.HasSwitch(switches::kDisableDevTools);
257    web_prefs.javascript_enabled =
258        !command_line.HasSwitch(switches::kDisableJavaScript) &&
259        prefs->GetBoolean(prefs::kWebKitJavascriptEnabled);
260    web_prefs.web_security_enabled =
261        !command_line.HasSwitch(switches::kDisableWebSecurity) &&
262        prefs->GetBoolean(prefs::kWebKitWebSecurityEnabled);
263    web_prefs.plugins_enabled =
264        !command_line.HasSwitch(switches::kDisablePlugins) &&
265        prefs->GetBoolean(prefs::kWebKitPluginsEnabled);
266    web_prefs.java_enabled =
267        !command_line.HasSwitch(switches::kDisableJava) &&
268        prefs->GetBoolean(prefs::kWebKitJavaEnabled);
269    web_prefs.loads_images_automatically =
270        prefs->GetBoolean(prefs::kWebKitLoadsImagesAutomatically);
271    web_prefs.uses_page_cache =
272        command_line.HasSwitch(switches::kEnableFastback);
273    web_prefs.remote_fonts_enabled =
274        !command_line.HasSwitch(switches::kDisableRemoteFonts);
275    web_prefs.xss_auditor_enabled =
276        !command_line.HasSwitch(switches::kDisableXSSAuditor);
277    web_prefs.application_cache_enabled =
278        !command_line.HasSwitch(switches::kDisableApplicationCache);
279
280    web_prefs.local_storage_enabled =
281        !command_line.HasSwitch(switches::kDisableLocalStorage);
282    web_prefs.databases_enabled =
283        !command_line.HasSwitch(switches::kDisableDatabases);
284    web_prefs.webaudio_enabled =
285        command_line.HasSwitch(switches::kEnableWebAudio);
286    web_prefs.experimental_webgl_enabled =
287        gpu_enabled() &&
288        !command_line.HasSwitch(switches::kDisable3DAPIs) &&
289        !command_line.HasSwitch(switches::kDisableExperimentalWebGL);
290    web_prefs.gl_multisampling_enabled =
291        !command_line.HasSwitch(switches::kDisableGLMultisampling);
292    web_prefs.site_specific_quirks_enabled =
293        !command_line.HasSwitch(switches::kDisableSiteSpecificQuirks);
294    web_prefs.allow_file_access_from_file_urls =
295        command_line.HasSwitch(switches::kAllowFileAccessFromFiles);
296    web_prefs.show_composited_layer_borders =
297        command_line.HasSwitch(switches::kShowCompositedLayerBorders);
298    web_prefs.show_composited_layer_tree =
299        command_line.HasSwitch(switches::kShowCompositedLayerTree);
300    web_prefs.show_fps_counter =
301        command_line.HasSwitch(switches::kShowFPSCounter);
302    web_prefs.accelerated_compositing_enabled =
303        gpu_enabled() &&
304        !command_line.HasSwitch(switches::kDisableAcceleratedCompositing);
305    web_prefs.force_compositing_mode =
306        command_line.HasSwitch(switches::kForceCompositingMode);
307    web_prefs.accelerated_2d_canvas_enabled =
308        gpu_enabled() &&
309        command_line.HasSwitch(switches::kEnableAccelerated2dCanvas);
310    web_prefs.accelerated_drawing_enabled =
311        gpu_enabled() &&
312        command_line.HasSwitch(switches::kEnableAcceleratedDrawing);
313    web_prefs.accelerated_layers_enabled =
314        !command_line.HasSwitch(switches::kDisableAcceleratedLayers);
315    web_prefs.composite_to_texture_enabled =
316        command_line.HasSwitch(switches::kEnableCompositeToTexture);
317    web_prefs.accelerated_plugins_enabled =
318        command_line.HasSwitch(switches::kEnableAcceleratedPlugins);
319    web_prefs.accelerated_video_enabled =
320        !command_line.HasSwitch(switches::kDisableAcceleratedVideo);
321    web_prefs.memory_info_enabled =
322        command_line.HasSwitch(switches::kEnableMemoryInfo);
323    web_prefs.interactive_form_validation_enabled =
324        !command_line.HasSwitch(switches::kDisableInteractiveFormValidation);
325    web_prefs.fullscreen_enabled =
326        command_line.HasSwitch(switches::kEnableFullScreen);
327
328    // The user stylesheet watcher may not exist in a testing profile.
329    if (profile->GetUserStyleSheetWatcher()) {
330      web_prefs.user_style_sheet_enabled = true;
331      web_prefs.user_style_sheet_location =
332          profile->GetUserStyleSheetWatcher()->user_style_sheet();
333    } else {
334      web_prefs.user_style_sheet_enabled = false;
335    }
336  }
337
338  {  // Certain GPU features might have been blacklisted.
339    GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance();
340    DCHECK(gpu_data_manager);
341    uint32 blacklist_flags = gpu_data_manager->GetGpuFeatureFlags().flags();
342    if (blacklist_flags & GpuFeatureFlags::kGpuFeatureAcceleratedCompositing)
343      web_prefs.accelerated_compositing_enabled = false;
344    if (blacklist_flags & GpuFeatureFlags::kGpuFeatureWebgl)
345      web_prefs.experimental_webgl_enabled = false;
346    if (blacklist_flags & GpuFeatureFlags::kGpuFeatureMultisampling)
347      web_prefs.gl_multisampling_enabled = false;
348  }
349
350  web_prefs.uses_universal_detector =
351      prefs->GetBoolean(prefs::kWebKitUsesUniversalDetector);
352  web_prefs.text_areas_are_resizable =
353      prefs->GetBoolean(prefs::kWebKitTextAreasAreResizable);
354  web_prefs.hyperlink_auditing_enabled =
355      prefs->GetBoolean(prefs::kEnableHyperlinkAuditing);
356
357  // Make sure we will set the default_encoding with canonical encoding name.
358  web_prefs.default_encoding =
359      CharacterEncoding::GetCanonicalEncodingNameByAliasName(
360          web_prefs.default_encoding);
361  if (web_prefs.default_encoding.empty()) {
362    prefs->ClearPref(prefs::kDefaultCharset);
363    web_prefs.default_encoding = prefs->GetString(prefs::kDefaultCharset);
364  }
365  DCHECK(!web_prefs.default_encoding.empty());
366
367  if (is_web_ui) {
368    web_prefs.loads_images_automatically = true;
369    web_prefs.javascript_enabled = true;
370  }
371
372  return web_prefs;
373}
374
375void RenderViewHostDelegateHelper::UpdateInspectorSetting(
376    Profile* profile, const std::string& key, const std::string& value) {
377  DictionaryPrefUpdate update(profile->GetPrefs(),
378                              prefs::kWebKitInspectorSettings);
379  DictionaryValue* inspector_settings = update.Get();
380  inspector_settings->SetWithoutPathExpansion(key,
381                                              Value::CreateStringValue(value));
382}
383
384void RenderViewHostDelegateHelper::ClearInspectorSettings(Profile* profile) {
385  profile->GetPrefs()->ClearPref(prefs::kWebKitInspectorSettings);
386}
387