summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui
diff options
context:
space:
mode:
authortfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-27 05:58:07 +0000
committertfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-27 05:58:07 +0000
commit265a149061df91fb2c794a877994a6b9b17c0395 (patch)
treede806aa83fd520d92ede0e06923744158e73eeaa /chrome/browser/ui
parent4ff6ce9702a91c52892786464b15f3c8588d4070 (diff)
downloadchromium_src-265a149061df91fb2c794a877994a6b9b17c0395.zip
chromium_src-265a149061df91fb2c794a877994a6b9b17c0395.tar.gz
chromium_src-265a149061df91fb2c794a877994a6b9b17c0395.tar.bz2
WebUI: Move more files from chrome/browser/webui to chrome/browser/ui/webui.
I'm moving the files I have found with: $ ls chrome/browser/webui | grep _ui BUG=59946 TEST=trybots Review URL: http://codereview.chromium.org/6599024 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76183 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/ui')
-rw-r--r--chrome/browser/ui/browser.cc4
-rw-r--r--chrome/browser/ui/browser_init.cc2
-rw-r--r--chrome/browser/ui/cocoa/constrained_html_delegate_mac.mm4
-rw-r--r--chrome/browser/ui/cocoa/html_dialog_window_controller.h2
-rw-r--r--chrome/browser/ui/cocoa/html_dialog_window_controller.mm2
-rw-r--r--chrome/browser/ui/cocoa/html_dialog_window_controller_unittest.mm2
-rw-r--r--chrome/browser/ui/gtk/browser_window_gtk.cc2
-rw-r--r--chrome/browser/ui/gtk/constrained_html_delegate_gtk.cc4
-rw-r--r--chrome/browser/ui/gtk/html_dialog_gtk.cc2
-rw-r--r--chrome/browser/ui/gtk/html_dialog_gtk.h2
-rw-r--r--chrome/browser/ui/views/constrained_html_delegate_gtk.cc4
-rw-r--r--chrome/browser/ui/views/constrained_html_delegate_win.cc4
-rw-r--r--chrome/browser/ui/views/frame/browser_view.cc2
-rw-r--r--chrome/browser/ui/views/html_dialog_view.h2
-rw-r--r--chrome/browser/ui/views/html_dialog_view_browsertest.cc2
-rw-r--r--chrome/browser/ui/views/keyboard_overlay_delegate.cc2
-rw-r--r--chrome/browser/ui/views/keyboard_overlay_delegate.h2
-rw-r--r--chrome/browser/ui/views/options/general_page_view.cc2
-rw-r--r--chrome/browser/ui/views/select_file_dialog.cc2
-rw-r--r--chrome/browser/ui/views/textfield_views.cc2
-rw-r--r--chrome/browser/ui/webui/bookmarks_ui.cc60
-rw-r--r--chrome/browser/ui/webui/bookmarks_ui.h45
-rw-r--r--chrome/browser/ui/webui/bookmarks_ui_uitest.cc154
-rw-r--r--chrome/browser/ui/webui/bug_report_ui.cc745
-rw-r--r--chrome/browser/ui/webui/bug_report_ui.h31
-rw-r--r--chrome/browser/ui/webui/conflicts_ui.cc215
-rw-r--r--chrome/browser/ui/webui/conflicts_ui.h28
-rw-r--r--chrome/browser/ui/webui/constrained_html_ui.cc67
-rw-r--r--chrome/browser/ui/webui/constrained_html_ui.h64
-rw-r--r--chrome/browser/ui/webui/constrained_html_ui_browsertest.cc74
-rw-r--r--chrome/browser/ui/webui/crashes_ui.cc212
-rw-r--r--chrome/browser/ui/webui/crashes_ui.h23
-rw-r--r--chrome/browser/ui/webui/devtools_ui.cc16
-rw-r--r--chrome/browser/ui/webui/devtools_ui.h22
-rw-r--r--chrome/browser/ui/webui/downloads_ui.cc145
-rw-r--r--chrome/browser/ui/webui/downloads_ui.h23
-rw-r--r--chrome/browser/ui/webui/filebrowse_ui.cc1272
-rw-r--r--chrome/browser/ui/webui/filebrowse_ui.h39
-rw-r--r--chrome/browser/ui/webui/flags_ui.cc204
-rw-r--r--chrome/browser/ui/webui/flags_ui.h25
-rw-r--r--chrome/browser/ui/webui/gpu_internals_ui.cc405
-rw-r--r--chrome/browser/ui/webui/gpu_internals_ui.h20
-rw-r--r--chrome/browser/ui/webui/history2_ui.cc413
-rw-r--r--chrome/browser/ui/webui/history2_ui.h112
-rw-r--r--chrome/browser/ui/webui/history_ui.cc401
-rw-r--r--chrome/browser/ui/webui/history_ui.h108
-rw-r--r--chrome/browser/ui/webui/html_dialog_ui.cc88
-rw-r--r--chrome/browser/ui/webui/html_dialog_ui.h120
-rw-r--r--chrome/browser/ui/webui/keyboard_ui.cc49
-rw-r--r--chrome/browser/ui/webui/keyboard_ui.h42
-rw-r--r--chrome/browser/ui/webui/mediaplayer_ui.cc613
-rw-r--r--chrome/browser/ui/webui/mediaplayer_ui.h161
-rw-r--r--chrome/browser/ui/webui/net_internals_ui.cc1315
-rw-r--r--chrome/browser/ui/webui/net_internals_ui.h19
-rw-r--r--chrome/browser/ui/webui/new_tab_ui.cc604
-rw-r--r--chrome/browser/ui/webui/new_tab_ui.h123
-rw-r--r--chrome/browser/ui/webui/new_tab_ui_uitest.cc183
-rw-r--r--chrome/browser/ui/webui/plugins_ui.cc374
-rw-r--r--chrome/browser/ui/webui/plugins_ui.h25
-rw-r--r--chrome/browser/ui/webui/print_preview_ui.cc36
-rw-r--r--chrome/browser/ui/webui/print_preview_ui.h31
-rw-r--r--chrome/browser/ui/webui/print_preview_ui_html_source.cc123
-rw-r--r--chrome/browser/ui/webui/print_preview_ui_html_source.h51
-rw-r--r--chrome/browser/ui/webui/print_preview_ui_html_source_unittest.cc60
-rw-r--r--chrome/browser/ui/webui/print_preview_ui_uitest.cc75
-rw-r--r--chrome/browser/ui/webui/remoting_ui.cc83
-rw-r--r--chrome/browser/ui/webui/remoting_ui.h25
-rw-r--r--chrome/browser/ui/webui/slideshow_ui.cc284
-rw-r--r--chrome/browser/ui/webui/slideshow_ui.h19
-rw-r--r--chrome/browser/ui/webui/sync_internals_ui.cc83
-rw-r--r--chrome/browser/ui/webui/sync_internals_ui.h53
-rw-r--r--chrome/browser/ui/webui/sync_internals_ui_unittest.cc226
-rw-r--r--chrome/browser/ui/webui/textfields_ui.cc74
-rw-r--r--chrome/browser/ui/webui/textfields_ui.h71
74 files changed, 9958 insertions, 25 deletions
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 11ac457..51ff4b5 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -84,12 +84,12 @@
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/browser/ui/tabs/dock_info.h"
#include "chrome/browser/ui/tabs/tab_menu_model.h"
+#include "chrome/browser/ui/webui/bug_report_ui.h"
+#include "chrome/browser/ui/webui/filebrowse_ui.h"
#include "chrome/browser/ui/webui/options/content_settings_handler.h"
#include "chrome/browser/ui/window_sizer.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/webui/bug_report_ui.h"
-#include "chrome/browser/webui/filebrowse_ui.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/content_restriction.h"
diff --git a/chrome/browser/ui/browser_init.cc b/chrome/browser/ui/browser_init.cc
index d8cf4fc..a803d7b 100644
--- a/chrome/browser/ui/browser_init.cc
+++ b/chrome/browser/ui/browser_init.cc
@@ -93,7 +93,7 @@
#include "chrome/browser/chromeos/usb_mount_observer.h"
#include "chrome/browser/chromeos/wm_message_listener.h"
#include "chrome/browser/chromeos/wm_overview_controller.h"
-#include "chrome/browser/webui/mediaplayer_ui.h"
+#include "chrome/browser/ui/webui/mediaplayer_ui.h"
#endif
#if defined(HAVE_XINPUT2)
diff --git a/chrome/browser/ui/cocoa/constrained_html_delegate_mac.mm b/chrome/browser/ui/cocoa/constrained_html_delegate_mac.mm
index 52efd8e..61b9a75 100644
--- a/chrome/browser/ui/cocoa/constrained_html_delegate_mac.mm
+++ b/chrome/browser/ui/cocoa/constrained_html_delegate_mac.mm
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/webui/constrained_html_ui.h"
+#include "chrome/browser/ui/webui/constrained_html_ui.h"
#include "base/scoped_nsobject.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/cocoa/constrained_window_mac.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/browser/webui/html_dialog_tab_contents_delegate.h"
#import <Cocoa/Cocoa.h>
#include "ipc/ipc_message.h"
diff --git a/chrome/browser/ui/cocoa/html_dialog_window_controller.h b/chrome/browser/ui/cocoa/html_dialog_window_controller.h
index 89c3bf4..e5660da 100644
--- a/chrome/browser/ui/cocoa/html_dialog_window_controller.h
+++ b/chrome/browser/ui/cocoa/html_dialog_window_controller.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
class HtmlDialogWindowDelegateBridge;
class Profile;
diff --git a/chrome/browser/ui/cocoa/html_dialog_window_controller.mm b/chrome/browser/ui/cocoa/html_dialog_window_controller.mm
index d9fd127..68d25df 100644
--- a/chrome/browser/ui/cocoa/html_dialog_window_controller.mm
+++ b/chrome/browser/ui/cocoa/html_dialog_window_controller.mm
@@ -12,8 +12,8 @@
#import "chrome/browser/ui/browser_dialogs.h"
#import "chrome/browser/ui/cocoa/browser_command_executor.h"
#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/browser/webui/html_dialog_tab_contents_delegate.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "ipc/ipc_message.h"
#include "ui/base/keycodes/keyboard_codes.h"
diff --git a/chrome/browser/ui/cocoa/html_dialog_window_controller_unittest.mm b/chrome/browser/ui/cocoa/html_dialog_window_controller_unittest.mm
index a8c9927..b8e2c66 100644
--- a/chrome/browser/ui/cocoa/html_dialog_window_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/html_dialog_window_controller_unittest.mm
@@ -13,7 +13,7 @@
#include "base/sys_string_conversions.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/test/browser_with_test_window_test.h"
#include "chrome/test/testing_profile.h"
#include "content/browser/webui/web_ui.h"
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc
index b31becfc..e6b6eb4 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.cc
+++ b/chrome/browser/ui/gtk/browser_window_gtk.cc
@@ -73,8 +73,8 @@
#include "chrome/browser/ui/gtk/update_recommended_dialog.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/webui/bug_report_ui.h"
#include "chrome/browser/ui/window_sizer.h"
-#include "chrome/browser/webui/bug_report_ui.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/ui/gtk/constrained_html_delegate_gtk.cc b/chrome/browser/ui/gtk/constrained_html_delegate_gtk.cc
index 670d4cb..689125f 100644
--- a/chrome/browser/ui/gtk/constrained_html_delegate_gtk.cc
+++ b/chrome/browser/ui/gtk/constrained_html_delegate_gtk.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/webui/constrained_html_ui.h"
+#include "chrome/browser/ui/webui/constrained_html_ui.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/gtk/constrained_window_gtk.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/tab_contents_container_gtk.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/browser/webui/html_dialog_tab_contents_delegate.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
#include "chrome/common/notification_source.h"
#include "ipc/ipc_message.h"
#include "ui/gfx/rect.h"
diff --git a/chrome/browser/ui/gtk/html_dialog_gtk.cc b/chrome/browser/ui/gtk/html_dialog_gtk.cc
index 72ed2a1..e064b09 100644
--- a/chrome/browser/ui/gtk/html_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/html_dialog_gtk.cc
@@ -13,7 +13,7 @@
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/tab_contents_container_gtk.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "ipc/ipc_message.h"
diff --git a/chrome/browser/ui/gtk/html_dialog_gtk.h b/chrome/browser/ui/gtk/html_dialog_gtk.h
index 25f0fdb..11cbcca 100644
--- a/chrome/browser/ui/gtk/html_dialog_gtk.h
+++ b/chrome/browser/ui/gtk/html_dialog_gtk.h
@@ -10,8 +10,8 @@
#include <vector>
#include "base/scoped_ptr.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/browser/webui/html_dialog_tab_contents_delegate.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
#include "ui/base/gtk/gtk_signal.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
diff --git a/chrome/browser/ui/views/constrained_html_delegate_gtk.cc b/chrome/browser/ui/views/constrained_html_delegate_gtk.cc
index 7b48fc4..df9ba4f 100644
--- a/chrome/browser/ui/views/constrained_html_delegate_gtk.cc
+++ b/chrome/browser/ui/views/constrained_html_delegate_gtk.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/webui/constrained_html_ui.h"
+#include "chrome/browser/ui/webui/constrained_html_ui.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/gtk/constrained_window_gtk.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/browser/webui/html_dialog_tab_contents_delegate.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
#include "ipc/ipc_message.h"
#include "ui/gfx/rect.h"
#include "views/widget/widget_gtk.h"
diff --git a/chrome/browser/ui/views/constrained_html_delegate_win.cc b/chrome/browser/ui/views/constrained_html_delegate_win.cc
index 744c4e0..b8d51c0 100644
--- a/chrome/browser/ui/views/constrained_html_delegate_win.cc
+++ b/chrome/browser/ui/views/constrained_html_delegate_win.cc
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/webui/constrained_html_ui.h"
+#include "chrome/browser/ui/webui/constrained_html_ui.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/browser/webui/html_dialog_tab_contents_delegate.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
#include "ipc/ipc_message.h"
#include "ui/gfx/rect.h"
#include "views/view.h"
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 7b3bdc3..e4e92a1 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -59,8 +59,8 @@
#include "chrome/browser/ui/views/toolbar_view.h"
#include "chrome/browser/ui/views/update_recommended_message_box.h"
#include "chrome/browser/ui/views/window.h"
+#include "chrome/browser/ui/webui/bug_report_ui.h"
#include "chrome/browser/ui/window_sizer.h"
-#include "chrome/browser/webui/bug_report_ui.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/native_window_notification_source.h"
diff --git a/chrome/browser/ui/views/html_dialog_view.h b/chrome/browser/ui/views/html_dialog_view.h
index 1a2d5cb..9329c1e 100644
--- a/chrome/browser/ui/views/html_dialog_view.h
+++ b/chrome/browser/ui/views/html_dialog_view.h
@@ -9,8 +9,8 @@
#include <string>
#include "chrome/browser/ui/views/dom_view.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/browser/webui/html_dialog_tab_contents_delegate.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
#include "ui/gfx/size.h"
#include "views/window/window_delegate.h"
diff --git a/chrome/browser/ui/views/html_dialog_view_browsertest.cc b/chrome/browser/ui/views/html_dialog_view_browsertest.cc
index d5f78d0..7862c85 100644
--- a/chrome/browser/ui/views/html_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/html_dialog_view_browsertest.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/views/html_dialog_view.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
diff --git a/chrome/browser/ui/views/keyboard_overlay_delegate.cc b/chrome/browser/ui/views/keyboard_overlay_delegate.cc
index 2b2fef3..2591b68 100644
--- a/chrome/browser/ui/views/keyboard_overlay_delegate.cc
+++ b/chrome/browser/ui/views/keyboard_overlay_delegate.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/chromeos/frame/bubble_window.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/views/html_dialog_view.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/views/keyboard_overlay_delegate.h b/chrome/browser/ui/views/keyboard_overlay_delegate.h
index c85b17b..75ab7ea 100644
--- a/chrome/browser/ui/views/keyboard_overlay_delegate.h
+++ b/chrome/browser/ui/views/keyboard_overlay_delegate.h
@@ -5,7 +5,7 @@
#ifndef CHROME_BROWSER_UI_VIEWS_KEYBOARD_OVERLAY_DELEGATE_H_
#define CHROME_BROWSER_UI_VIEWS_KEYBOARD_OVERLAY_DELEGATE_H_
-#include "chrome/browser/webui/html_dialog_ui.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "ui/gfx/native_widget_types.h"
class KeyboardOverlayDelegate : public HtmlDialogUIDelegate {
diff --git a/chrome/browser/ui/views/options/general_page_view.cc b/chrome/browser/ui/views/options/general_page_view.cc
index ce3027b..0996b4a 100644
--- a/chrome/browser/ui/views/options/general_page_view.cc
+++ b/chrome/browser/ui/views/options/general_page_view.cc
@@ -28,7 +28,7 @@
#include "chrome/browser/ui/views/keyword_editor_view.h"
#include "chrome/browser/ui/views/options/managed_prefs_banner_view.h"
#include "chrome/browser/ui/views/options/options_group_view.h"
-#include "chrome/browser/webui/new_tab_ui.h"
+#include "chrome/browser/ui/webui/new_tab_ui.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/ui/views/select_file_dialog.cc b/chrome/browser/ui/views/select_file_dialog.cc
index b4a08ef..4ea81b7 100644
--- a/chrome/browser/ui/views/select_file_dialog.cc
+++ b/chrome/browser/ui/views/select_file_dialog.cc
@@ -19,7 +19,7 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/views/html_dialog_view.h"
-#include "chrome/browser/webui/html_dialog_ui.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/views/textfield_views.cc b/chrome/browser/ui/views/textfield_views.cc
index 8e1268f..b4aabdb 100644
--- a/chrome/browser/ui/views/textfield_views.cc
+++ b/chrome/browser/ui/views/textfield_views.cc
@@ -7,7 +7,7 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/webui/textfields_ui.h"
+#include "chrome/browser/ui/webui/textfields_ui.h"
TextfieldViews::TextfieldViews() : DOMView() {}
diff --git a/chrome/browser/ui/webui/bookmarks_ui.cc b/chrome/browser/ui/webui/bookmarks_ui.cc
new file mode 100644
index 0000000..3cdd0f4
--- /dev/null
+++ b/chrome/browser/ui/webui/bookmarks_ui.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/bookmarks_ui.h"
+
+#include "base/message_loop.h"
+#include "base/ref_counted_memory.h"
+#include "base/singleton.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/url_constants.h"
+#include "grit/theme_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// BookmarksUIHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+BookmarksUIHTMLSource::BookmarksUIHTMLSource()
+ : DataSource(chrome::kChromeUIBookmarksHost, MessageLoop::current()) {
+}
+
+void BookmarksUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ NOTREACHED() << "We should never get here since the extension should have"
+ << "been triggered";
+
+ SendResponse(request_id, NULL);
+}
+
+std::string BookmarksUIHTMLSource::GetMimeType(const std::string& path) const {
+ NOTREACHED() << "We should never get here since the extension should have"
+ << "been triggered";
+ return "text/html";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// BookmarksUI
+//
+////////////////////////////////////////////////////////////////////////////////
+
+BookmarksUI::BookmarksUI(TabContents* contents) : WebUI(contents) {
+ BookmarksUIHTMLSource* html_source = new BookmarksUIHTMLSource();
+
+ // Set up the chrome://bookmarks/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+// static
+RefCountedMemory* BookmarksUI::GetFaviconResourceBytes() {
+ return ResourceBundle::GetSharedInstance().
+ LoadDataResourceBytes(IDR_BOOKMARKS_FAVICON);
+}
diff --git a/chrome/browser/ui/webui/bookmarks_ui.h b/chrome/browser/ui/webui/bookmarks_ui.h
new file mode 100644
index 0000000..10c5113
--- /dev/null
+++ b/chrome/browser/ui/webui/bookmarks_ui.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_BOOKMARKS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_BOOKMARKS_UI_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "content/browser/webui/web_ui.h"
+
+class GURL;
+class RefCountedMemory;
+
+// This class provides the source for chrome://bookmarks/
+class BookmarksUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ BookmarksUIHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string& path) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BookmarksUIHTMLSource);
+};
+
+// This class is used to hook up chrome://bookmarks/ which in turn gets
+// overridden by an extension.
+class BookmarksUI : public WebUI {
+ public:
+ explicit BookmarksUI(TabContents* contents);
+
+ static RefCountedMemory* GetFaviconResourceBytes();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BookmarksUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_BOOKMARKS_UI_H_
diff --git a/chrome/browser/ui/webui/bookmarks_ui_uitest.cc b/chrome/browser/ui/webui/bookmarks_ui_uitest.cc
new file mode 100644
index 0000000..04c37f6
--- /dev/null
+++ b/chrome/browser/ui/webui/bookmarks_ui_uitest.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/ui/ui_test.h"
+
+#include "base/test/test_timeouts.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "chrome/test/automation/window_proxy.h"
+
+class BookmarksUITest : public UITest {
+ public:
+ BookmarksUITest() {
+ dom_automation_enabled_ = true;
+ }
+
+ bool WaitForBookmarksUI(TabProxy* tab) {
+ return WaitUntilJavaScriptCondition(tab, L"",
+ L"domAutomationController.send("
+ L" location.protocol == 'chrome-extension:' && "
+ L" document.readyState == 'complete')",
+ TestTimeouts::huge_test_timeout_ms());
+ }
+
+ scoped_refptr<TabProxy> GetBookmarksUITab() {
+ scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ EXPECT_TRUE(browser.get());
+ if (!browser.get())
+ return NULL;
+ scoped_refptr<TabProxy> tab = browser->GetActiveTab();
+ EXPECT_TRUE(tab.get());
+ if (!tab.get())
+ return NULL;
+ bool success = tab->NavigateToURL(GURL(chrome::kChromeUIBookmarksURL));
+ EXPECT_TRUE(success);
+ if (!success)
+ return NULL;
+ success = WaitForBookmarksUI(tab);
+ EXPECT_TRUE(success);
+ if (!success)
+ return NULL;
+ return tab;
+ }
+
+ void AssertIsBookmarksPage(TabProxy* tab) {
+ // tab->GetCurrentURL is not up to date.
+ GURL url;
+ std::wstring out;
+ ASSERT_TRUE(tab->ExecuteAndExtractString(L"",
+ L"domAutomationController.send(location.protocol)", &out));
+ ASSERT_EQ(L"chrome-extension:", out);
+ ASSERT_TRUE(tab->ExecuteAndExtractString(L"",
+ L"domAutomationController.send(location.pathname)", &out));
+ ASSERT_EQ(L"/main.html", out);
+ }
+};
+
+// http://code.google.com/p/chromium/issues/detail?id=39532
+TEST_F(BookmarksUITest, FLAKY_ShouldRedirectToExtension) {
+ scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+
+ int tab_count = -1;
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+
+ // Navigate to chrome
+ scoped_refptr<TabProxy> tab = browser->GetActiveTab();
+ ASSERT_TRUE(tab.get());
+
+ ASSERT_TRUE(tab->NavigateToURL(GURL(chrome::kChromeUIBookmarksURL)));
+
+ // At this point the URL is chrome://bookmarks. We need to wait for the
+ // redirect to happen.
+ ASSERT_TRUE(WaitForBookmarksUI(tab));
+
+ AssertIsBookmarksPage(tab);
+}
+
+TEST_F(BookmarksUITest, CommandOpensBookmarksTab) {
+ scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+
+ int tab_count = -1;
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+
+ // Bring up the bookmarks manager tab.
+ ASSERT_TRUE(browser->RunCommand(IDC_SHOW_BOOKMARK_MANAGER));
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+
+ scoped_refptr<TabProxy> tab = browser->GetActiveTab();
+ ASSERT_TRUE(tab.get());
+
+ ASSERT_TRUE(WaitForBookmarksUI(tab));
+
+ AssertIsBookmarksPage(tab);
+}
+
+TEST_F(BookmarksUITest, CommandAgainGoesBackToBookmarksTab) {
+ scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+
+ int tab_count = -1;
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+
+ // Bring up the bookmarks manager tab.
+ ASSERT_TRUE(browser->RunCommand(IDC_SHOW_BOOKMARK_MANAGER));
+ ASSERT_TRUE(browser->WaitForTabToBecomeActive(
+ 1, TestTimeouts::action_max_timeout_ms()));
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+
+ scoped_refptr<TabProxy> tab = browser->GetActiveTab();
+ ASSERT_TRUE(tab.get());
+ ASSERT_TRUE(WaitForBookmarksUI(tab));
+ AssertIsBookmarksPage(tab);
+
+ // Switch to first tab and run command again.
+ ASSERT_TRUE(browser->ActivateTab(0));
+ ASSERT_TRUE(browser->WaitForTabToBecomeActive(
+ 0, TestTimeouts::action_max_timeout_ms()));
+ ASSERT_TRUE(browser->RunCommand(IDC_SHOW_BOOKMARK_MANAGER));
+
+ // Ensure the bookmarks ui tab is active.
+ ASSERT_TRUE(browser->WaitForTabToBecomeActive(
+ 1, TestTimeouts::action_max_timeout_ms()));
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+}
+
+TEST_F(BookmarksUITest, TwoCommandsOneTab) {
+ scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+
+ int tab_count = -1;
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+
+ ASSERT_TRUE(browser->RunCommand(IDC_SHOW_BOOKMARK_MANAGER));
+ ASSERT_TRUE(browser->RunCommand(IDC_SHOW_BOOKMARK_MANAGER));
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+}
+
+TEST_F(BookmarksUITest, BookmarksLoaded) {
+ scoped_refptr<TabProxy> tab = GetBookmarksUITab();
+ ASSERT_TRUE(tab.get());
+}
diff --git a/chrome/browser/ui/webui/bug_report_ui.cc b/chrome/browser/ui/webui/bug_report_ui.cc
new file mode 100644
index 0000000..1b99d6a
--- /dev/null
+++ b/chrome/browser/ui/webui/bug_report_ui.cc
@@ -0,0 +1,745 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/bug_report_ui.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/singleton.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "base/weak_ptr.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/bug_report_data.h"
+#include "chrome/browser/bug_report_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/window_snapshot/window_snapshot.h"
+#include "chrome/browser/webui/screenshot_source.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/rect.h"
+
+#if defined(OS_CHROMEOS)
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/synchronization/waitable_event.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/syslogs_library.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#endif
+
+namespace {
+
+const char kScreenshotBaseUrl[] = "chrome://screenshots/";
+const char kCurrentScreenshotUrl[] = "chrome://screenshots/current";
+#if defined(OS_CHROMEOS)
+const char kSavedScreenshotsUrl[] = "chrome://screenshots/saved/";
+
+const char kScreenshotPattern[] = "*.png";
+const char kScreenshotsRelativePath[] = "/Screenshots";
+
+const size_t kMaxSavedScreenshots = 2;
+#endif
+
+#if defined(OS_CHROMEOS)
+
+void GetSavedScreenshots(std::vector<std::string>* saved_screenshots,
+ base::WaitableEvent* done) {
+ saved_screenshots->clear();
+
+ FilePath fileshelf_path;
+ if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
+ &fileshelf_path)) {
+ done->Signal();
+ return;
+ }
+
+ // TODO(rkc): Change this to use FilePath.Append() once the cros
+ // issue with it is fixed
+ FilePath screenshots_path(fileshelf_path.value() +
+ std::string(kScreenshotsRelativePath));
+ file_util::FileEnumerator screenshots(screenshots_path, false,
+ file_util::FileEnumerator::FILES,
+ std::string(kScreenshotPattern));
+ FilePath screenshot = screenshots.Next();
+ while (!screenshot.empty()) {
+ saved_screenshots->push_back(std::string(kSavedScreenshotsUrl) +
+ screenshot.BaseName().value());
+ if (saved_screenshots->size() >= kMaxSavedScreenshots)
+ break;
+
+ screenshot = screenshots.Next();
+ }
+ done->Signal();
+}
+
+// This fuction posts a task to the file thread to create/list all the current
+// and saved screenshots.
+void GetScreenshotUrls(std::vector<std::string>* saved_screenshots) {
+ base::WaitableEvent done(true, false);
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ NewRunnableFunction(&GetSavedScreenshots,
+ saved_screenshots, &done));
+ done.Wait();
+}
+
+std::string GetUserEmail() {
+ chromeos::UserManager* manager = chromeos::UserManager::Get();
+ if (!manager)
+ return std::string();
+ else
+ return manager->logged_in_user().email();
+}
+#endif
+
+// Returns the index of the feedback tab if already open, -1 otherwise
+int GetIndexOfFeedbackTab(Browser* browser) {
+ GURL bug_report_url(chrome::kChromeUIBugReportURL);
+ for (int i = 0; i < browser->tab_count(); ++i) {
+ TabContents* tab = browser->GetTabContentsAt(i);
+ if (tab && tab->GetURL().GetWithEmptyPath() == bug_report_url)
+ return i;
+ }
+
+ return -1;
+}
+
+} // namespace
+
+
+namespace browser {
+
+// TODO(rkc): Eventually find a better way to do this
+std::vector<unsigned char>* last_screenshot_png = 0;
+gfx::Rect screen_size;
+
+void RefreshLastScreenshot(Browser* browser) {
+ if (last_screenshot_png)
+ last_screenshot_png->clear();
+ else
+ last_screenshot_png = new std::vector<unsigned char>;
+
+ gfx::NativeWindow native_window = browser->window()->GetNativeHandle();
+ screen_size = browser::GrabWindowSnapshot(native_window, last_screenshot_png);
+}
+
+void ShowHtmlBugReportView(Browser* browser) {
+ // First check if we're already open (we cannot depend on ShowSingletonTab
+ // for this functionality since we need to make *sure* we never get
+ // instantiated again while we are open - with singleton tabs, that can
+ // happen)
+ int feedback_tab_index = GetIndexOfFeedbackTab(browser);
+ if (feedback_tab_index >=0) {
+ // Do not refresh screenshot, do not create a new tab
+ browser->SelectTabContentsAt(feedback_tab_index, true);
+ return;
+ }
+
+ RefreshLastScreenshot(browser);
+ std::string bug_report_url = std::string(chrome::kChromeUIBugReportURL) +
+ "#" + base::IntToString(browser->selected_index());
+ browser->ShowSingletonTab(GURL(bug_report_url), false);
+}
+
+} // namespace browser
+
+
+class BugReportUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ explicit BugReportUIHTMLSource(base::StringPiece html);
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ base::StringPiece bug_report_html_;
+ ~BugReportUIHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(BugReportUIHTMLSource);
+};
+
+// The handler for Javascript messages related to the "bug report" dialog
+class BugReportHandler : public WebUIMessageHandler,
+ public base::SupportsWeakPtr<BugReportHandler> {
+ public:
+ explicit BugReportHandler(TabContents* tab);
+ virtual ~BugReportHandler();
+
+ // Init work after Attach.
+ base::StringPiece Init();
+
+ // WebUIMessageHandler implementation.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+ virtual void RegisterMessages();
+
+ private:
+ void HandleGetDialogDefaults(const ListValue* args);
+ void HandleRefreshCurrentScreenshot(const ListValue* args);
+#if defined(OS_CHROMEOS)
+ void HandleRefreshSavedScreenshots(const ListValue* args);
+#endif
+ void HandleSendReport(const ListValue* args);
+ void HandleCancel(const ListValue* args);
+ void HandleOpenSystemTab(const ListValue* args);
+
+ void SetupScreenshotsSource();
+ void ClobberScreenshotsSource();
+
+ void CancelFeedbackCollection();
+ void CloseFeedbackTab();
+
+ TabContents* tab_;
+ ScreenshotSource* screenshot_source_;
+
+ BugReportData* bug_report_;
+ std::string target_tab_url_;
+#if defined(OS_CHROMEOS)
+ // Variables to track SyslogsLibrary::RequestSyslogs callback.
+ chromeos::SyslogsLibrary::Handle syslogs_handle_;
+ CancelableRequestConsumer syslogs_consumer_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(BugReportHandler);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// BugReportHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+BugReportUIHTMLSource::BugReportUIHTMLSource(base::StringPiece html)
+ : DataSource(chrome::kChromeUIBugReportHost, MessageLoop::current()) {
+ bug_report_html_ = html;
+}
+
+void BugReportUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ localized_strings.SetString(std::string("title"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_TITLE));
+ localized_strings.SetString(std::string("page-title"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_REPORT_PAGE_TITLE));
+ localized_strings.SetString(std::string("issue-with"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_ISSUE_WITH));
+ localized_strings.SetString(std::string("page-url"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_REPORT_URL_LABEL));
+ localized_strings.SetString(std::string("description"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_DESCRIPTION_LABEL));
+ localized_strings.SetString(std::string("current-screenshot"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_SCREENSHOT_LABEL));
+ localized_strings.SetString(std::string("saved-screenshot"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_SAVED_SCREENSHOT_LABEL));
+#if defined(OS_CHROMEOS)
+ localized_strings.SetString(std::string("user-email"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_USER_EMAIL_LABEL));
+ localized_strings.SetString(std::string("sysinfo"),
+ l10n_util::GetStringUTF8(
+ IDS_BUGREPORT_INCLUDE_SYSTEM_INFORMATION_CHKBOX));
+
+ localized_strings.SetString(std::string("currentscreenshots"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_CURRENT_SCREENSHOTS));
+ localized_strings.SetString(std::string("savedscreenshots"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_SAVED_SCREENSHOTS));
+
+ localized_strings.SetString(std::string("choose-different-screenshot"),
+ l10n_util::GetStringUTF8(
+ IDS_BUGREPORT_CHOOSE_DIFFERENT_SCREENSHOT));
+ localized_strings.SetString(std::string("choose-original-screenshot"),
+ l10n_util::GetStringUTF8(
+ IDS_BUGREPORT_CHOOSE_ORIGINAL_SCREENSHOT));
+#else
+ localized_strings.SetString(std::string("currentscreenshots"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_INCLUDE_NEW_SCREEN_IMAGE));
+#endif
+ localized_strings.SetString(std::string("noscreenshot"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_INCLUDE_NO_SCREENSHOT));
+
+ localized_strings.SetString(std::string("send-report"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_SEND_REPORT));
+ localized_strings.SetString(std::string("cancel"),
+ l10n_util::GetStringUTF8(IDS_CANCEL));
+
+ // Option strings for the "issue with" drop-down.
+ localized_strings.SetString(std::string("issue-choose"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_CHOOSE_ISSUE));
+
+ localized_strings.SetString(std::string("no-issue-selected"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_NO_ISSUE_SELECTED));
+
+ localized_strings.SetString(std::string("no-description"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_NO_DESCRIPTION));
+
+ localized_strings.SetString(std::string("no-saved-screenshots"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_NO_SAVED_SCREENSHOTS_HELP));
+
+ localized_strings.SetString(std::string("privacy-note"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_PRIVACY_NOTE));
+
+ // TODO(rkc): Find some way to ensure this order of dropdowns is in sync
+ // with the order in the userfeedback ChromeData proto buffer
+#if defined(OS_CHROMEOS)
+ // Dropdown for ChromeOS:
+ //
+ // Connectivity
+ // Sync
+ // Crash
+ // Page Formatting
+ // Extensions or Apps
+ // Standby or Resume
+ // Phishing Page
+ // General Feedback/Other
+
+ localized_strings.SetString(std::string("issue-connectivity"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_CONNECTIVITY));
+ localized_strings.SetString(std::string("issue-sync"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_SYNC));
+ localized_strings.SetString(std::string("issue-crashes"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_CRASHES));
+ localized_strings.SetString(std::string("issue-page-formatting"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_FORMATTING));
+ localized_strings.SetString(std::string("issue-extensions"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_EXTENSIONS));
+ localized_strings.SetString(std::string("issue-standby"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_STANDBY_RESUME));
+ localized_strings.SetString(std::string("issue-phishing"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_PHISHING_PAGE));
+ localized_strings.SetString(std::string("issue-other"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_GENERAL));
+#else
+ // Dropdown for Chrome:
+ //
+ // Page formatting or layout
+ // Pages not loading
+ // Plug-ins (e.g. Adobe Flash Player, Quicktime, etc)
+ // Tabs or windows
+ // Synced preferences
+ // Crashes
+ // Extensions or apps
+ // Phishing
+ // Other
+
+ localized_strings.SetString(std::string("issue-page-formatting"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_FORMATTING));
+ localized_strings.SetString(std::string("issue-page-load"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_LOAD));
+ localized_strings.SetString(std::string("issue-plugins"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_PLUGINS));
+ localized_strings.SetString(std::string("issue-tabs"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_TABS));
+ localized_strings.SetString(std::string("issue-sync"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_SYNC));
+ localized_strings.SetString(std::string("issue-crashes"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_CRASHES));
+ localized_strings.SetString(std::string("issue-extensions"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_EXTENSIONS));
+ localized_strings.SetString(std::string("issue-phishing"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_PHISHING_PAGE));
+ localized_strings.SetString(std::string("issue-other"),
+ l10n_util::GetStringUTF8(IDS_BUGREPORT_OTHER));
+#endif
+
+ SetFontAndTextDirection(&localized_strings);
+
+ const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
+ bug_report_html_, &localized_strings);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// BugReportData
+//
+////////////////////////////////////////////////////////////////////////////////
+void BugReportData::SendReport() {
+#if defined(OS_CHROMEOS)
+ // In case we already got the syslogs and sent the report, leave
+ if (sent_report_) return;
+ // Set send_report_ so that no one else processes SendReport
+ sent_report_ = true;
+#endif
+
+ int image_data_size = image_.size();
+ char* image_data = image_data_size ?
+ reinterpret_cast<char*>(&(image_.front())) : NULL;
+ BugReportUtil::SendReport(profile_
+ , problem_type_
+ , page_url_
+ , description_
+ , image_data
+ , image_data_size
+ , browser::screen_size.width()
+ , browser::screen_size.height()
+#if defined(OS_CHROMEOS)
+ , user_email_
+ , zip_content_ ? zip_content_->c_str() : NULL
+ , zip_content_ ? zip_content_->length() : 0
+ , send_sys_info_ ? sys_info_ : NULL
+#endif
+ );
+
+#if defined(OS_CHROMEOS)
+ if (sys_info_) {
+ delete sys_info_;
+ sys_info_ = NULL;
+ }
+ if (zip_content_) {
+ delete zip_content_;
+ zip_content_ = NULL;
+ }
+#endif
+
+ // Once the report has been sent, this object has no purpose in life, delete
+ // ourselves.
+ delete this;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// BugReportHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+BugReportHandler::BugReportHandler(TabContents* tab)
+ : tab_(tab),
+ screenshot_source_(NULL),
+ bug_report_(NULL)
+#if defined(OS_CHROMEOS)
+ , syslogs_handle_(0)
+#endif
+{
+}
+
+BugReportHandler::~BugReportHandler() {
+ // Just in case we didn't send off bug_report_ to SendReport
+ if (bug_report_) {
+ // If we're deleting the report object, cancel feedback collection first
+ CancelFeedbackCollection();
+ delete bug_report_;
+ }
+}
+
+void BugReportHandler::ClobberScreenshotsSource() {
+ // Re-create our screenshots data source (this clobbers the last source)
+ // setting the screenshot to NULL, effectively disabling the source
+ // TODO(rkc): Once there is a method to 'remove' a source, change this code
+ tab_->profile()->GetChromeURLDataManager()->AddDataSource(
+ new ScreenshotSource(NULL));
+
+ // clobber last screenshot
+ if (browser::last_screenshot_png)
+ browser::last_screenshot_png->clear();
+}
+
+void BugReportHandler::SetupScreenshotsSource() {
+ // If we don't already have a screenshot source object created, create one.
+ if (!screenshot_source_)
+ screenshot_source_ = new ScreenshotSource(
+ browser::last_screenshot_png);
+
+ // Add the source to the data manager.
+ tab_->profile()->GetChromeURLDataManager()->AddDataSource(screenshot_source_);
+}
+
+WebUIMessageHandler* BugReportHandler::Attach(WebUI* web_ui) {
+ SetupScreenshotsSource();
+ return WebUIMessageHandler::Attach(web_ui);
+}
+
+base::StringPiece BugReportHandler::Init() {
+ std::string page_url;
+ if (tab_->controller().GetActiveEntry()) {
+ page_url = tab_->controller().GetActiveEntry()->url().spec();
+ }
+
+ std::string params = page_url.substr(strlen(chrome::kChromeUIBugReportURL));
+ // Erase the # - the first character.
+ if (params.length())
+ params.erase(params.begin(), params.begin() + 1);
+
+ int index = 0;
+ if (!base::StringToInt(params, &index)) {
+ return base::StringPiece(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_BUGREPORT_HTML_INVALID));
+ }
+
+ Browser* browser = BrowserList::GetLastActive();
+ // Sanity checks.
+ if (((index == 0) && (params != "0")) || !browser ||
+ index >= browser->tab_count()) {
+ return base::StringPiece(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_BUGREPORT_HTML_INVALID));
+ }
+
+ TabContents* target_tab = browser->GetTabContentsAt(index);
+ if (target_tab) {
+ target_tab_url_ = target_tab->GetURL().spec();
+ }
+
+ // Setup the screenshot source after we've verified input is legit.
+ SetupScreenshotsSource();
+
+ return base::StringPiece(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_BUGREPORT_HTML));
+}
+
+void BugReportHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("getDialogDefaults",
+ NewCallback(this, &BugReportHandler::HandleGetDialogDefaults));
+ web_ui_->RegisterMessageCallback("refreshCurrentScreenshot",
+ NewCallback(this, &BugReportHandler::HandleRefreshCurrentScreenshot));
+#if defined(OS_CHROMEOS)
+ web_ui_->RegisterMessageCallback("refreshSavedScreenshots",
+ NewCallback(this, &BugReportHandler::HandleRefreshSavedScreenshots));
+#endif
+ web_ui_->RegisterMessageCallback("sendReport",
+ NewCallback(this, &BugReportHandler::HandleSendReport));
+ web_ui_->RegisterMessageCallback("cancel",
+ NewCallback(this, &BugReportHandler::HandleCancel));
+ web_ui_->RegisterMessageCallback("openSystemTab",
+ NewCallback(this, &BugReportHandler::HandleOpenSystemTab));
+}
+
+void BugReportHandler::HandleGetDialogDefaults(const ListValue*) {
+ bug_report_ = new BugReportData();
+
+ // send back values which the dialog js needs initially
+ ListValue dialog_defaults;
+
+ // 0: current url
+ if (target_tab_url_.length())
+ dialog_defaults.Append(new StringValue(target_tab_url_));
+ else
+ dialog_defaults.Append(new StringValue(""));
+
+#if defined(OS_CHROMEOS)
+ // 1: about:system
+ dialog_defaults.Append(new StringValue(chrome::kChromeUISystemInfoURL));
+ // Trigger the request for system information here.
+ chromeos::SyslogsLibrary* syslogs_lib =
+ chromeos::CrosLibrary::Get()->GetSyslogsLibrary();
+ if (syslogs_lib) {
+ syslogs_handle_ = syslogs_lib->RequestSyslogs(
+ true, true, &syslogs_consumer_,
+ NewCallback(bug_report_, &BugReportData::SyslogsComplete));
+ }
+ // 2: user e-mail
+ dialog_defaults.Append(new StringValue(GetUserEmail()));
+#endif
+
+ web_ui_->CallJavascriptFunction(L"setupDialogDefaults", dialog_defaults);
+}
+
+void BugReportHandler::HandleRefreshCurrentScreenshot(const ListValue*) {
+ std::string current_screenshot(kCurrentScreenshotUrl);
+ StringValue screenshot(current_screenshot);
+ web_ui_->CallJavascriptFunction(L"setupCurrentScreenshot", screenshot);
+}
+
+
+#if defined(OS_CHROMEOS)
+void BugReportHandler::HandleRefreshSavedScreenshots(const ListValue*) {
+ std::vector<std::string> saved_screenshots;
+ GetScreenshotUrls(&saved_screenshots);
+
+ ListValue screenshots_list;
+ for (size_t i = 0; i < saved_screenshots.size(); ++i)
+ screenshots_list.Append(new StringValue(saved_screenshots[i]));
+ web_ui_->CallJavascriptFunction(L"setupSavedScreenshots", screenshots_list);
+}
+#endif
+
+
+void BugReportHandler::HandleSendReport(const ListValue* list_value) {
+ if (!bug_report_) {
+ LOG(ERROR) << "Bug report hasn't been intialized yet.";
+ return;
+ }
+
+ ListValue::const_iterator i = list_value->begin();
+ if (i == list_value->end()) {
+ LOG(ERROR) << "Incorrect data passed to sendReport.";
+ return;
+ }
+
+ // #0 - Problem type.
+ int problem_type;
+ std::string problem_type_str;
+ (*i)->GetAsString(&problem_type_str);
+ if (!base::StringToInt(problem_type_str, &problem_type)) {
+ LOG(ERROR) << "Incorrect data passed to sendReport.";
+ return;
+ }
+ if (++i == list_value->end()) {
+ LOG(ERROR) << "Incorrect data passed to sendReport.";
+ return;
+ }
+
+ // #1 - Page url.
+ std::string page_url;
+ (*i)->GetAsString(&page_url);
+ if (++i == list_value->end()) {
+ LOG(ERROR) << "Incorrect data passed to sendReport.";
+ return;
+ }
+
+ // #2 - Description.
+ std::string description;
+ (*i)->GetAsString(&description);
+ if (++i == list_value->end()) {
+ LOG(ERROR) << "Incorrect data passed to sendReport.";
+ return;
+ }
+
+ // #3 - Screenshot to send.
+ std::string screenshot_path;
+ (*i)->GetAsString(&screenshot_path);
+ screenshot_path.erase(0, strlen(kScreenshotBaseUrl));
+
+ // Get the image to send in the report.
+ std::vector<unsigned char> image;
+ if (screenshot_path.size() > 0) {
+ image = screenshot_source_->GetScreenshot(screenshot_path);
+ }
+
+#if defined(OS_CHROMEOS)
+ if (++i == list_value->end()) {
+ LOG(ERROR) << "Incorrect data passed to sendReport.";
+ return;
+ }
+
+ // #4 - User e-mail
+ std::string user_email;
+ (*i)->GetAsString(&user_email);
+ if (++i == list_value->end()) {
+ LOG(ERROR) << "Incorrect data passed to sendReport.";
+ return;
+ }
+
+ // #5 - System info checkbox.
+ std::string sys_info_checkbox;
+ (*i)->GetAsString(&sys_info_checkbox);
+ bool send_sys_info = (sys_info_checkbox == "true");
+
+ // If we aren't sending the sys_info, cancel the gathering of the syslogs.
+ if (!send_sys_info)
+ CancelFeedbackCollection();
+#endif
+
+ // Update the data in bug_report_ so it can be sent
+ bug_report_->UpdateData(web_ui_->GetProfile()
+ , target_tab_url_
+ , problem_type
+ , page_url
+ , description
+ , image
+#if defined(OS_CHROMEOS)
+ , user_email
+ , send_sys_info
+ , false // sent_report
+#endif
+ );
+
+#if defined(OS_CHROMEOS)
+ // If we don't require sys_info, or we have it, or we never requested it
+ // (because libcros failed to load), then send the report now.
+ // Otherwise, the report will get sent when we receive sys_info.
+ if (!send_sys_info || bug_report_->sys_info() != NULL ||
+ syslogs_handle_ == 0) {
+ bug_report_->SendReport();
+ }
+#else
+ bug_report_->SendReport();
+#endif
+ // Lose the pointer to the BugReportData object; the object will delete itself
+ // from SendReport, whether we called it, or will be called by the log
+ // completion routine.
+ bug_report_ = NULL;
+
+ // Whether we sent the report, or if it will be sent by the Syslogs complete
+ // function, close our feedback tab anyway, we have no more use for it.
+ CloseFeedbackTab();
+}
+
+void BugReportHandler::HandleCancel(const ListValue*) {
+ CloseFeedbackTab();
+}
+
+void BugReportHandler::HandleOpenSystemTab(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ BrowserList::GetLastActive()->OpenSystemTabAndActivate();
+#endif
+}
+
+void BugReportHandler::CancelFeedbackCollection() {
+#if defined(OS_CHROMEOS)
+ if (syslogs_handle_ != 0) {
+ chromeos::SyslogsLibrary* syslogs_lib =
+ chromeos::CrosLibrary::Get()->GetSyslogsLibrary();
+ if (syslogs_lib)
+ syslogs_lib->CancelRequest(syslogs_handle_);
+ }
+#endif
+}
+
+void BugReportHandler::CloseFeedbackTab() {
+ Browser* browser = BrowserList::GetLastActive();
+ if (browser) {
+ browser->CloseTabContents(tab_);
+ } else {
+ LOG(FATAL) << "Failed to get last active browser.";
+ }
+ ClobberScreenshotsSource();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// BugReportUI
+//
+////////////////////////////////////////////////////////////////////////////////
+BugReportUI::BugReportUI(TabContents* tab) : HtmlDialogUI(tab) {
+ BugReportHandler* handler = new BugReportHandler(tab);
+ AddMessageHandler((handler)->Attach(this));
+
+ // The handler's init will specify which html
+ // resource we'll display to the user
+ BugReportUIHTMLSource* html_source =
+ new BugReportUIHTMLSource(handler->Init());
+ // Set up the chrome://bugreport/ source.
+ tab->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
diff --git a/chrome/browser/ui/webui/bug_report_ui.h b/chrome/browser/ui/webui/bug_report_ui.h
new file mode 100644
index 0000000..e4814d5
--- /dev/null
+++ b/chrome/browser/ui/webui/bug_report_ui.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_BUG_REPORT_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_BUG_REPORT_UI_H_
+
+#include "chrome/browser/ui/views/window.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
+
+namespace gfx {
+class Rect;
+} // namespace gfx
+
+class Browser;
+class NSWindow;
+class TabContents;
+
+namespace browser {
+void ShowHtmlBugReportView(Browser* browser);
+} // namespace browser
+
+class BugReportUI : public HtmlDialogUI {
+ public:
+ explicit BugReportUI(TabContents* contents);
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(BugReportUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_BUG_REPORT_UI_H_
diff --git a/chrome/browser/ui/webui/conflicts_ui.cc b/chrome/browser/ui/webui/conflicts_ui.cc
new file mode 100644
index 0000000..5ff5a65
--- /dev/null
+++ b/chrome/browser/ui/webui/conflicts_ui.cc
@@ -0,0 +1,215 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/conflicts_ui.h"
+
+#if defined(OS_WIN)
+
+#include <string>
+
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/enumerate_modules_model_win.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ConflictsUIHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+class ConflictsUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ ConflictsUIHTMLSource()
+ : DataSource(chrome::kChromeUIConflictsHost, MessageLoop::current()) {}
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConflictsUIHTMLSource);
+};
+
+void ConflictsUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ // Strings used in the JsTemplate file.
+ DictionaryValue localized_strings;
+ localized_strings.SetString("modulesLongTitle",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_CHECK_PAGE_TITLE_LONG));
+ localized_strings.SetString("modulesBlurb",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_EXPLANATION_TEXT));
+ localized_strings.SetString("moduleSuspectedBad",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_CHECK_WARNING_SUSPECTED));
+ localized_strings.SetString("moduleConfirmedBad",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_CHECK_WARNING_CONFIRMED));
+ localized_strings.SetString("helpCenterLink",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_HELP_CENTER_LINK));
+ localized_strings.SetString("investigatingText",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_CHECK_INVESTIGATING));
+ localized_strings.SetString("modulesNoneLoaded",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_NO_MODULES_LOADED));
+ localized_strings.SetString("headerSoftware",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_HEADER_SOFTWARE));
+ localized_strings.SetString("headerSignedBy",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_HEADER_SIGNED_BY));
+ localized_strings.SetString("headerLocation",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_HEADER_LOCATION));
+ localized_strings.SetString("headerVersion",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_HEADER_VERSION));
+ localized_strings.SetString("headerHelpTip",
+ l10n_util::GetStringUTF16(IDS_CONFLICTS_HEADER_HELP_TIP));
+
+ ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece flags_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_ABOUT_CONFLICTS_HTML));
+ std::string full_html(flags_html.data(), flags_html.size());
+ jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
+ jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
+ jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
+ jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ConflictsDOMHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// The handler for JavaScript messages for the about:flags page.
+class ConflictsDOMHandler : public WebUIMessageHandler,
+ public NotificationObserver {
+ public:
+ ConflictsDOMHandler() {}
+ virtual ~ConflictsDOMHandler() {}
+
+ // WebUIMessageHandler implementation.
+ virtual void RegisterMessages();
+
+ // Callback for the "requestModuleList" message.
+ void HandleRequestModuleList(const ListValue* args);
+
+ private:
+ void SendModuleList();
+
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConflictsDOMHandler);
+};
+
+void ConflictsDOMHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("requestModuleList",
+ NewCallback(this, &ConflictsDOMHandler::HandleRequestModuleList));
+}
+
+void ConflictsDOMHandler::HandleRequestModuleList(const ListValue* args) {
+ // This request is handled asynchronously. See Observe for when we reply back.
+ registrar_.Add(this, NotificationType::MODULE_LIST_ENUMERATED,
+ NotificationService::AllSources());
+ EnumerateModulesModel::GetInstance()->ScanNow();
+}
+
+void ConflictsDOMHandler::SendModuleList() {
+ EnumerateModulesModel* loaded_modules = EnumerateModulesModel::GetInstance();
+ ListValue* list = loaded_modules->GetModuleList();
+ DictionaryValue results;
+ results.Set("moduleList", list);
+
+ // Add the section title and the total count for bad modules found.
+ int confirmed_bad = loaded_modules->confirmed_bad_modules_detected();
+ int suspected_bad = loaded_modules->suspected_bad_modules_detected();
+ string16 table_title;
+ if (!confirmed_bad && !suspected_bad) {
+ table_title += l10n_util::GetStringFUTF16(
+ IDS_CONFLICTS_CHECK_PAGE_TABLE_TITLE_SUFFIX_ONE,
+ base::IntToString16(list->GetSize()));
+ } else {
+ table_title += l10n_util::GetStringFUTF16(
+ IDS_CONFLICTS_CHECK_PAGE_TABLE_TITLE_SUFFIX_TWO,
+ base::IntToString16(list->GetSize()),
+ base::IntToString16(confirmed_bad),
+ base::IntToString16(suspected_bad));
+ }
+ results.SetString("modulesTableTitle", table_title);
+
+ web_ui_->CallJavascriptFunction(L"returnModuleList", results);
+}
+
+void ConflictsDOMHandler::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::MODULE_LIST_ENUMERATED:
+ SendModuleList();
+ registrar_.RemoveAll();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// ConflictsUI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+ConflictsUI::ConflictsUI(TabContents* contents) : WebUI(contents) {
+ UserMetrics::RecordAction(
+ UserMetricsAction("ViewAboutConflicts"), contents->profile());
+
+ AddMessageHandler((new ConflictsDOMHandler())->Attach(this));
+
+ ConflictsUIHTMLSource* html_source = new ConflictsUIHTMLSource();
+
+ // Set up the about:conflicts source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+// static
+RefCountedMemory* ConflictsUI::GetFaviconResourceBytes() {
+ return ResourceBundle::GetSharedInstance().
+ LoadDataResourceBytes(IDR_CONFLICT_FAVICON);
+}
+
+#endif
diff --git a/chrome/browser/ui/webui/conflicts_ui.h b/chrome/browser/ui/webui/conflicts_ui.h
new file mode 100644
index 0000000..3e05ccf
--- /dev/null
+++ b/chrome/browser/ui/webui/conflicts_ui.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_CONFLICTS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CONFLICTS_UI_H_
+#pragma once
+
+#include "content/browser/webui/web_ui.h"
+
+#if defined(OS_WIN)
+
+class RefCountedMemory;
+
+// The Web UI handler for about:conflicts.
+class ConflictsUI : public WebUI {
+ public:
+ explicit ConflictsUI(TabContents* contents);
+
+ static RefCountedMemory* GetFaviconResourceBytes();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConflictsUI);
+};
+
+#endif
+
+#endif // CHROME_BROWSER_UI_WEBUI_CONFLICTS_UI_H_
diff --git a/chrome/browser/ui/webui/constrained_html_ui.cc b/chrome/browser/ui/webui/constrained_html_ui.cc
new file mode 100644
index 0000000..68dd024
--- /dev/null
+++ b/chrome/browser/ui/webui/constrained_html_ui.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/constrained_html_ui.h"
+
+#include "base/lazy_instance.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
+#include "chrome/common/bindings_policy.h"
+#include "content/browser/webui/web_ui_util.h"
+
+static base::LazyInstance<PropertyAccessor<ConstrainedHtmlUIDelegate*> >
+ g_constrained_html_ui_property_accessor(base::LINKER_INITIALIZED);
+
+ConstrainedHtmlUI::ConstrainedHtmlUI(TabContents* contents)
+ : WebUI(contents) {
+}
+
+ConstrainedHtmlUI::~ConstrainedHtmlUI() {
+}
+
+void ConstrainedHtmlUI::RenderViewCreated(
+ RenderViewHost* render_view_host) {
+ ConstrainedHtmlUIDelegate* delegate = GetConstrainedDelegate();
+ if (!delegate)
+ return;
+
+ HtmlDialogUIDelegate* dialog_delegate = delegate->GetHtmlDialogUIDelegate();
+ std::vector<WebUIMessageHandler*> handlers;
+ dialog_delegate->GetWebUIMessageHandlers(&handlers);
+ render_view_host->SetWebUIProperty("dialogArguments",
+ dialog_delegate->GetDialogArgs());
+ for (std::vector<WebUIMessageHandler*>::iterator it = handlers.begin();
+ it != handlers.end(); ++it) {
+ (*it)->Attach(this);
+ AddMessageHandler(*it);
+ }
+
+ // Add a "DialogClose" callback which matches HTMLDialogUI behavior.
+ RegisterMessageCallback("DialogClose",
+ NewCallback(this, &ConstrainedHtmlUI::OnDialogClose));
+}
+
+void ConstrainedHtmlUI::OnDialogClose(const ListValue* args) {
+ ConstrainedHtmlUIDelegate* delegate = GetConstrainedDelegate();
+ if (!delegate)
+ return;
+
+ delegate->GetHtmlDialogUIDelegate()->OnDialogClosed(
+ web_ui_util::GetJsonResponseFromFirstArgumentInList(args));
+ delegate->OnDialogClose();
+}
+
+ConstrainedHtmlUIDelegate*
+ ConstrainedHtmlUI::GetConstrainedDelegate() {
+ ConstrainedHtmlUIDelegate** property =
+ GetPropertyAccessor().GetProperty(tab_contents()->property_bag());
+ return property ? *property : NULL;
+}
+
+// static
+PropertyAccessor<ConstrainedHtmlUIDelegate*>&
+ ConstrainedHtmlUI::GetPropertyAccessor() {
+ return g_constrained_html_ui_property_accessor.Get();
+}
diff --git a/chrome/browser/ui/webui/constrained_html_ui.h b/chrome/browser/ui/webui/constrained_html_ui.h
new file mode 100644
index 0000000..55da2db
--- /dev/null
+++ b/chrome/browser/ui/webui/constrained_html_ui.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_CONSTRAINED_HTML_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CONSTRAINED_HTML_UI_H_
+#pragma once
+
+#include <vector>
+
+#include "chrome/browser/tab_contents/constrained_window.h"
+#include "chrome/common/property_bag.h"
+#include "content/browser/webui/web_ui.h"
+
+class HtmlDialogUIDelegate;
+class Profile;
+class RenderViewHost;
+class TabContents;
+
+class ConstrainedHtmlUIDelegate {
+ public:
+ virtual HtmlDialogUIDelegate* GetHtmlDialogUIDelegate() = 0;
+
+ // Called when the dialog should close.
+ virtual void OnDialogClose() = 0;
+};
+
+// ConstrainedHtmlUI is a facility to show HTML WebUI content
+// in a tab-modal constrained dialog. It is implemented as an adapter
+// between an HtmlDialogUI object and a ConstrainedWindow object.
+//
+// Since ConstrainedWindow requires platform-specific delegate
+// implementations, this class is just a factory stub.
+class ConstrainedHtmlUI : public WebUI {
+ public:
+ explicit ConstrainedHtmlUI(TabContents* contents);
+ virtual ~ConstrainedHtmlUI();
+
+ virtual void RenderViewCreated(RenderViewHost* render_view_host);
+
+ // Create a constrained HTML dialog. The actual object that gets created
+ // is a ConstrainedHtmlUIDelegate, which later triggers construction of a
+ // ConstrainedHtmlUI object.
+ static void CreateConstrainedHtmlDialog(Profile* profile,
+ HtmlDialogUIDelegate* delegate,
+ TabContents* overshadowed);
+
+ // Returns a property accessor that can be used to set the
+ // ConstrainedHtmlUIDelegate property on a TabContents.
+ static PropertyAccessor<ConstrainedHtmlUIDelegate*>&
+ GetPropertyAccessor();
+
+ private:
+ // Returns the TabContents' PropertyBag's ConstrainedHtmlUIDelegate.
+ // Returns NULL if that property is not set.
+ ConstrainedHtmlUIDelegate* GetConstrainedDelegate();
+
+ // JS Message Handler
+ void OnDialogClose(const ListValue* args);
+
+ DISALLOW_COPY_AND_ASSIGN(ConstrainedHtmlUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_CONSTRAINED_HTML_UI_H_
diff --git a/chrome/browser/ui/webui/constrained_html_ui_browsertest.cc b/chrome/browser/ui/webui/constrained_html_ui_browsertest.cc
new file mode 100644
index 0000000..5b40613
--- /dev/null
+++ b/chrome/browser/ui/webui/constrained_html_ui_browsertest.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/ui/ui_test.h"
+
+#include "base/file_path.h"
+#include "base/message_loop.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/webui/constrained_html_ui.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/ui_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Eq;
+
+namespace {
+
+class TestHtmlDialogUIDelegate : public HtmlDialogUIDelegate {
+ public:
+ TestHtmlDialogUIDelegate() {}
+ virtual ~TestHtmlDialogUIDelegate() {}
+
+ // HTMLDialogUIDelegate implementation:
+ virtual bool IsDialogModal() const {
+ return true;
+ }
+ virtual std::wstring GetDialogTitle() const {
+ return std::wstring(L"Test");
+ }
+ virtual GURL GetDialogContentURL() const {
+ return GURL(chrome::kChromeUIConstrainedHTMLTestURL);
+ }
+ virtual void GetWebUIMessageHandlers(
+ std::vector<WebUIMessageHandler*>* handlers) const {}
+ virtual void GetDialogSize(gfx::Size* size) const {
+ size->set_width(400);
+ size->set_height(400);
+ }
+ virtual std::string GetDialogArgs() const {
+ return std::string();
+ }
+ virtual void OnDialogClosed(const std::string& json_retval) { }
+ virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) {
+ if (out_close_dialog)
+ *out_close_dialog = true;
+ }
+ virtual bool ShouldShowDialogTitle() const { return true; }
+};
+
+} // namespace
+
+class ConstrainedHtmlDialogBrowserTest : public InProcessBrowserTest {
+ public:
+ ConstrainedHtmlDialogBrowserTest() {}
+};
+
+// Tests that opening/closing the constrained window won't crash it.
+IN_PROC_BROWSER_TEST_F(ConstrainedHtmlDialogBrowserTest, BasicTest) {
+ // The delegate deletes itself.
+ HtmlDialogUIDelegate* delegate = new TestHtmlDialogUIDelegate();
+ TabContents* tab_contents = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(tab_contents != NULL);
+
+ ConstrainedHtmlUI::CreateConstrainedHtmlDialog(browser()->profile(),
+ delegate,
+ tab_contents);
+
+ ASSERT_EQ(1U, tab_contents->constrained_window_count());
+}
diff --git a/chrome/browser/ui/webui/crashes_ui.cc b/chrome/browser/ui/webui/crashes_ui.cc
new file mode 100644
index 0000000..d4bb435
--- /dev/null
+++ b/chrome/browser/ui/webui/crashes_ui.cc
@@ -0,0 +1,212 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/crashes_ui.h"
+
+#include "base/i18n/time_formatting.h"
+#include "base/ref_counted_memory.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/crash_upload_list.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CrashesUIHTMLSource
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class CrashesUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ CrashesUIHTMLSource()
+ : DataSource(chrome::kChromeUICrashesHost, MessageLoop::current()) {}
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ ~CrashesUIHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(CrashesUIHTMLSource);
+};
+
+void CrashesUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ localized_strings.SetString("crashesTitle",
+ l10n_util::GetStringUTF16(IDS_CRASHES_TITLE));
+ localized_strings.SetString("crashCountFormat",
+ l10n_util::GetStringUTF16(IDS_CRASHES_CRASH_COUNT_BANNER_FORMAT));
+ localized_strings.SetString("crashHeaderFormat",
+ l10n_util::GetStringUTF16(IDS_CRASHES_CRASH_HEADER_FORMAT));
+ localized_strings.SetString("crashTimeFormat",
+ l10n_util::GetStringUTF16(IDS_CRASHES_CRASH_TIME_FORMAT));
+ localized_strings.SetString("bugLinkText",
+ l10n_util::GetStringUTF16(IDS_CRASHES_BUG_LINK_LABEL));
+ localized_strings.SetString("noCrashesMessage",
+ l10n_util::GetStringUTF16(IDS_CRASHES_NO_CRASHES_MESSAGE));
+ localized_strings.SetString("disabledHeader",
+ l10n_util::GetStringUTF16(IDS_CRASHES_DISABLED_HEADER));
+ localized_strings.SetString("disabledMessage",
+ l10n_util::GetStringUTF16(IDS_CRASHES_DISABLED_MESSAGE));
+
+ ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece crashes_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_CRASHES_HTML));
+ std::string full_html =
+ jstemplate_builder::GetI18nTemplateHtml(crashes_html, &localized_strings);
+ jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// CrashesDOMHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// The handler for Javascript messages for the chrome://crashes/ page.
+class CrashesDOMHandler : public WebUIMessageHandler,
+ public CrashUploadList::Delegate {
+ public:
+ explicit CrashesDOMHandler();
+ virtual ~CrashesDOMHandler();
+
+ // WebUIMessageHandler implementation.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+ virtual void RegisterMessages();
+
+ // CrashUploadList::Delegate implemenation.
+ virtual void OnCrashListAvailable();
+
+ private:
+ // Asynchronously fetches the list of crashes. Called from JS.
+ void HandleRequestCrashes(const ListValue* args);
+
+ // Sends the recent crashes list JS.
+ void UpdateUI();
+
+ // Returns whether or not crash reporting is enabled.
+ bool CrashReportingEnabled() const;
+
+ scoped_refptr<CrashUploadList> upload_list_;
+ bool list_available_;
+ bool js_request_pending_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrashesDOMHandler);
+};
+
+CrashesDOMHandler::CrashesDOMHandler()
+ : list_available_(false), js_request_pending_(false) {
+ upload_list_ = new CrashUploadList(this);
+}
+
+CrashesDOMHandler::~CrashesDOMHandler() {
+ upload_list_->ClearDelegate();
+}
+
+WebUIMessageHandler* CrashesDOMHandler::Attach(WebUI* web_ui) {
+ upload_list_->LoadCrashListAsynchronously();
+ return WebUIMessageHandler::Attach(web_ui);
+}
+
+void CrashesDOMHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("requestCrashList",
+ NewCallback(this, &CrashesDOMHandler::HandleRequestCrashes));
+}
+
+void CrashesDOMHandler::HandleRequestCrashes(const ListValue* args) {
+ if (!CrashReportingEnabled() || list_available_)
+ UpdateUI();
+ else
+ js_request_pending_ = true;
+}
+
+void CrashesDOMHandler::OnCrashListAvailable() {
+ list_available_ = true;
+ if (js_request_pending_)
+ UpdateUI();
+}
+
+void CrashesDOMHandler::UpdateUI() {
+ bool crash_reporting_enabled = CrashReportingEnabled();
+ ListValue crash_list;
+
+ if (crash_reporting_enabled) {
+ std::vector<CrashUploadList::CrashInfo> crashes;
+ upload_list_->GetUploadedCrashes(50, &crashes);
+
+ for (std::vector<CrashUploadList::CrashInfo>::iterator i = crashes.begin();
+ i != crashes.end(); ++i) {
+ DictionaryValue* crash = new DictionaryValue();
+ crash->SetString("id", i->crash_id);
+ crash->SetString("time",
+ base::TimeFormatFriendlyDateAndTime(i->crash_time));
+ crash_list.Append(crash);
+ }
+ }
+
+ FundamentalValue enabled(crash_reporting_enabled);
+
+ web_ui_->CallJavascriptFunction(L"updateCrashList", enabled, crash_list);
+}
+
+bool CrashesDOMHandler::CrashReportingEnabled() const {
+#if defined(GOOGLE_CHROME_BUILD)
+ PrefService* prefs = web_ui_->GetProfile()->GetPrefs();
+ return prefs->GetBoolean(prefs::kMetricsReportingEnabled);
+#else
+ return false;
+#endif
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CrashesUI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+CrashesUI::CrashesUI(TabContents* contents) : WebUI(contents) {
+ AddMessageHandler((new CrashesDOMHandler())->Attach(this));
+
+ CrashesUIHTMLSource* html_source = new CrashesUIHTMLSource();
+
+ // Set up the chrome://crashes/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+// static
+RefCountedMemory* CrashesUI::GetFaviconResourceBytes() {
+ return ResourceBundle::GetSharedInstance().
+ LoadDataResourceBytes(IDR_SAD_FAVICON);
+}
diff --git a/chrome/browser/ui/webui/crashes_ui.h b/chrome/browser/ui/webui/crashes_ui.h
new file mode 100644
index 0000000..919b260
--- /dev/null
+++ b/chrome/browser/ui/webui/crashes_ui.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_CRASHES_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CRASHES_UI_H_
+#pragma once
+
+#include "content/browser/webui/web_ui.h"
+
+class RefCountedMemory;
+
+class CrashesUI : public WebUI {
+ public:
+ explicit CrashesUI(TabContents* contents);
+
+ static RefCountedMemory* GetFaviconResourceBytes();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CrashesUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_CRASHES_UI_H_
diff --git a/chrome/browser/ui/webui/devtools_ui.cc b/chrome/browser/ui/webui/devtools_ui.cc
new file mode 100644
index 0000000..50aa4f3
--- /dev/null
+++ b/chrome/browser/ui/webui/devtools_ui.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/devtools_ui.h"
+
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/common/render_messages.h"
+
+DevToolsUI::DevToolsUI(TabContents* contents) : WebUI(contents) {
+}
+
+void DevToolsUI::RenderViewCreated(RenderViewHost* render_view_host) {
+ render_view_host->Send(new ViewMsg_SetupDevToolsClient(
+ render_view_host->routing_id()));
+}
diff --git a/chrome/browser/ui/webui/devtools_ui.h b/chrome/browser/ui/webui/devtools_ui.h
new file mode 100644
index 0000000..cca4e51
--- /dev/null
+++ b/chrome/browser/ui/webui/devtools_ui.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_DEVTOOLS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_DEVTOOLS_UI_H_
+#pragma once
+
+#include "content/browser/webui/web_ui.h"
+
+class DevToolsUI : public WebUI {
+ public:
+ explicit DevToolsUI(TabContents* contents);
+
+ // WebUI
+ virtual void RenderViewCreated(RenderViewHost* render_view_host);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DevToolsUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_DEVTOOLS_UI_H_
diff --git a/chrome/browser/ui/webui/downloads_ui.cc b/chrome/browser/ui/webui/downloads_ui.cc
new file mode 100644
index 0000000..96f7466
--- /dev/null
+++ b/chrome/browser/ui/webui/downloads_ui.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/downloads_ui.h"
+
+#include "base/singleton.h"
+#include "base/string_piece.h"
+#include "base/threading/thread.h"
+#include "base/values.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/defaults.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/browser/webui/downloads_dom_handler.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// DownloadsHTMLSource
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class DownloadsUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ DownloadsUIHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ ~DownloadsUIHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadsUIHTMLSource);
+};
+
+DownloadsUIHTMLSource::DownloadsUIHTMLSource()
+ : DataSource(chrome::kChromeUIDownloadsHost, MessageLoop::current()) {
+}
+
+void DownloadsUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_TITLE));
+ localized_strings.SetString("searchbutton",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_SEARCH_BUTTON));
+ localized_strings.SetString("no_results",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_SEARCH_BUTTON));
+ localized_strings.SetString("searchresultsfor",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_SEARCHRESULTSFOR));
+ localized_strings.SetString("downloads",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_TITLE));
+ localized_strings.SetString("clear_all",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_CLEAR_ALL));
+
+ // Status.
+ localized_strings.SetString("status_cancelled",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_TAB_CANCELED));
+ localized_strings.SetString("status_paused",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED));
+
+ // Dangerous file.
+ localized_strings.SetString("danger_desc",
+ l10n_util::GetStringUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD));
+ localized_strings.SetString("danger_save",
+ l10n_util::GetStringUTF16(IDS_SAVE_DOWNLOAD));
+ localized_strings.SetString("danger_discard",
+ l10n_util::GetStringUTF16(IDS_DISCARD_DOWNLOAD));
+
+ // Controls.
+ localized_strings.SetString("control_pause",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_PAUSE));
+ if (browser_defaults::kDownloadPageHasShowInFolder) {
+ localized_strings.SetString("control_showinfolder",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_SHOW));
+ }
+ localized_strings.SetString("control_retry",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_RETRY));
+ localized_strings.SetString("control_cancel",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_CANCEL));
+ localized_strings.SetString("control_resume",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_RESUME));
+ localized_strings.SetString("control_removefromlist",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_REMOVE));
+
+ SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece downloads_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_DOWNLOADS_HTML));
+ const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
+ downloads_html, &localized_strings);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// DownloadsUI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+DownloadsUI::DownloadsUI(TabContents* contents) : WebUI(contents) {
+ DownloadManager* dlm = GetProfile()->GetDownloadManager();
+
+ DownloadsDOMHandler* handler = new DownloadsDOMHandler(dlm);
+ AddMessageHandler(handler);
+ handler->Attach(this);
+ handler->Init();
+
+ DownloadsUIHTMLSource* html_source = new DownloadsUIHTMLSource();
+
+ // Set up the chrome://downloads/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+// static
+RefCountedMemory* DownloadsUI::GetFaviconResourceBytes() {
+ return ResourceBundle::GetSharedInstance().
+ LoadDataResourceBytes(IDR_DOWNLOADS_FAVICON);
+}
diff --git a/chrome/browser/ui/webui/downloads_ui.h b/chrome/browser/ui/webui/downloads_ui.h
new file mode 100644
index 0000000..41c1832
--- /dev/null
+++ b/chrome/browser/ui/webui/downloads_ui.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_DOWNLOADS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_DOWNLOADS_UI_H_
+#pragma once
+
+#include "content/browser/webui/web_ui.h"
+
+class RefCountedMemory;
+
+class DownloadsUI : public WebUI {
+ public:
+ explicit DownloadsUI(TabContents* contents);
+
+ static RefCountedMemory* GetFaviconResourceBytes();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DownloadsUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_DOWNLOADS_UI_H_
diff --git a/chrome/browser/ui/webui/filebrowse_ui.cc b/chrome/browser/ui/webui/filebrowse_ui.cc
new file mode 100644
index 0000000..6d6c1cb
--- /dev/null
+++ b/chrome/browser/ui/webui/filebrowse_ui.cc
@@ -0,0 +1,1272 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/filebrowse_ui.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/singleton.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/threading/thread.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "base/weak_ptr.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/download/download_item.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/webui/mediaplayer_ui.h"
+#include "chrome/browser/webui/favicon_source.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/net/url_fetcher.h"
+#include "chrome/common/time_format.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "net/base/escape.h"
+#include "net/url_request/url_request_file_job.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/mount_library.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#endif
+
+// Maximum number of search results to return in a given search. We should
+// eventually remove this.
+static const int kMaxSearchResults = 100;
+static const char kPropertyPath[] = "path";
+static const char kPropertyTitle[] = "title";
+static const char kPropertyDirectory[] = "isDirectory";
+static const char kPicasawebUserPrefix[] =
+ "http://picasaweb.google.com/data/feed/api/user/";
+static const char kPicasawebDefault[] = "/albumid/default";
+static const char kPicasawebDropBox[] = "/home";
+static const char kPicasawebBaseUrl[] = "http://picasaweb.google.com/";
+static const char kMediaPath[] = "/media";
+static const char kFilebrowseURLHash[] = "chrome://filebrowse#";
+static const int kPopupLeft = 0;
+static const int kPopupTop = 0;
+
+class FileBrowseUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ FileBrowseUIHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ ~FileBrowseUIHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(FileBrowseUIHTMLSource);
+};
+
+class TaskProxy;
+
+// The handler for Javascript messages related to the "filebrowse" view.
+class FilebrowseHandler : public net::DirectoryLister::DirectoryListerDelegate,
+ public WebUIMessageHandler,
+#if defined(OS_CHROMEOS)
+ public chromeos::MountLibrary::Observer,
+#endif
+ public base::SupportsWeakPtr<FilebrowseHandler>,
+ public URLFetcher::Delegate,
+ public DownloadManager::Observer,
+ public DownloadItem::Observer {
+ public:
+ FilebrowseHandler();
+ virtual ~FilebrowseHandler();
+
+ // Init work after Attach.
+ void Init();
+
+ // DirectoryLister::DirectoryListerDelegate methods:
+ virtual void OnListFile(
+ const net::DirectoryLister::DirectoryListerData& data);
+ virtual void OnListDone(int error);
+
+ // WebUIMessageHandler implementation.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+ virtual void RegisterMessages();
+
+#if defined(OS_CHROMEOS)
+ void MountChanged(chromeos::MountLibrary* obj,
+ chromeos::MountEventType evt,
+ const std::string& path);
+#endif
+
+ // DownloadItem::Observer interface
+ virtual void OnDownloadUpdated(DownloadItem* download);
+ virtual void OnDownloadFileCompleted(DownloadItem* download);
+ virtual void OnDownloadOpened(DownloadItem* download) { }
+
+ // DownloadManager::Observer interface
+ virtual void ModelChanged();
+
+ // Callback for the "getRoots" message.
+ void HandleGetRoots(const ListValue* args);
+
+ void GetChildrenForPath(const FilePath& path, bool is_refresh);
+
+ void OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const net::URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+
+ // Callback for the "getChildren" message.
+ void HandleGetChildren(const ListValue* args);
+ // Callback for the "refreshDirectory" message.
+ void HandleRefreshDirectory(const ListValue* args);
+ void HandleIsAdvancedEnabled(const ListValue* args);
+
+ // Callback for the "getMetadata" message.
+ void HandleGetMetadata(const ListValue* args);
+
+ // Callback for the "openNewWindow" message.
+ void OpenNewFullWindow(const ListValue* args);
+ void OpenNewPopupWindow(const ListValue* args);
+
+ // Callback for the "uploadToPicasaweb" message.
+ void UploadToPicasaweb(const ListValue* args);
+
+ // Callback for the "getDownloads" message.
+ void HandleGetDownloads(const ListValue* args);
+
+ void HandleCreateNewFolder(const ListValue* args);
+
+ void PlayMediaFile(const ListValue* args);
+ void EnqueueMediaFile(const ListValue* args);
+
+ void HandleDeleteFile(const ListValue* args);
+ void HandleCopyFile(const ListValue* value);
+ void CopyFile(const FilePath& src, const FilePath& dest, TaskProxy* task);
+ void DeleteFile(const FilePath& path, TaskProxy* task);
+ void FireDeleteComplete(const FilePath& path);
+ void FireCopyComplete(const FilePath& src, const FilePath& dest);
+
+ void HandlePauseToggleDownload(const ListValue* args);
+
+ void HandleCancelDownload(const ListValue* args);
+ void HandleAllowDownload(const ListValue* args);
+
+ void CreateNewFolder(const FilePath& path) const;
+
+ void ReadInFile();
+ void FireUploadComplete();
+
+ void SendPicasawebRequest();
+
+ // Callback for the "validateSavePath" message.
+ void HandleValidateSavePath(const ListValue* args);
+
+ // Validate a save path on file thread.
+ void ValidateSavePathOnFileThread(const FilePath& save_path, TaskProxy* task);
+
+ // Fire save path validation result to JS onValidatedSavePath.
+ void FireOnValidatedSavePathOnUIThread(bool valid, const FilePath& save_path);
+
+ private:
+
+ // Retrieves downloads from the DownloadManager and updates the page.
+ void UpdateDownloadList();
+
+ void OpenNewWindow(const ListValue* args, bool popup);
+
+ // Clear all download items and their observers.
+ void ClearDownloadItems();
+
+ // Send the current list of downloads to the page.
+ void SendCurrentDownloads();
+
+ void SendNewDownload(DownloadItem* download);
+
+ bool ValidateSaveDir(const FilePath& save_dir, bool exists) const;
+ bool AccessDisabled(const FilePath& path) const;
+
+ scoped_ptr<ListValue> filelist_value_;
+ FilePath currentpath_;
+ Profile* profile_;
+ TabContents* tab_contents_;
+ std::string current_file_contents_;
+ std::string current_file_uploaded_;
+ int upload_response_code_;
+ TaskProxy* current_task_;
+ scoped_refptr<net::DirectoryLister> lister_;
+ bool is_refresh_;
+ scoped_ptr<URLFetcher> fetch_;
+
+ DownloadManager* download_manager_;
+ typedef std::vector<DownloadItem*> DownloadList;
+ DownloadList active_download_items_;
+ DownloadList download_items_;
+ bool got_first_download_list_;
+ DISALLOW_COPY_AND_ASSIGN(FilebrowseHandler);
+};
+
+class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
+ public:
+ TaskProxy(const base::WeakPtr<FilebrowseHandler>& handler,
+ const FilePath& path, const FilePath& dest)
+ : handler_(handler),
+ src_(path),
+ dest_(dest) {}
+ TaskProxy(const base::WeakPtr<FilebrowseHandler>& handler,
+ const FilePath& path)
+ : handler_(handler),
+ src_(path) {}
+
+ // TaskProxy is created on the UI thread, so in some cases,
+ // we need to post back to the UI thread for destruction.
+ void DeleteOnUIThread() {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &TaskProxy::DoNothing));
+ }
+
+ void DoNothing() {}
+
+ void ReadInFileProxy() {
+ if (handler_)
+ handler_->ReadInFile();
+ DeleteOnUIThread();
+ }
+
+ void DeleteFetcher(URLFetcher* fetch) {
+ delete fetch;
+ }
+
+ void SendPicasawebRequestProxy() {
+ if (handler_)
+ handler_->SendPicasawebRequest();
+ DeleteOnUIThread();
+ }
+
+ void FireUploadCompleteProxy() {
+ if (handler_)
+ handler_->FireUploadComplete();
+ }
+
+ void DeleteFileProxy() {
+ if (handler_)
+ handler_->DeleteFile(src_, this);
+ }
+
+ void CopyFileProxy() {
+ if (handler_)
+ handler_->CopyFile(src_, dest_, this);
+ }
+
+ void CreateNewFolderProxy() {
+ if (handler_)
+ handler_->CreateNewFolder(src_);
+ DeleteOnUIThread();
+ }
+
+ void FireDeleteCompleteProxy() {
+ if (handler_)
+ handler_->FireDeleteComplete(src_);
+ }
+ void FireCopyCompleteProxy() {
+ if (handler_)
+ handler_->FireCopyComplete(src_, dest_);
+ }
+
+ void ValidateSavePathOnFileThread() {
+ if (handler_)
+ handler_->ValidateSavePathOnFileThread(src_, this);
+ }
+
+ void FireOnValidatedSavePathOnUIThread(bool valid) {
+ if (handler_)
+ handler_->FireOnValidatedSavePathOnUIThread(valid, src_);
+ }
+
+ private:
+ base::WeakPtr<FilebrowseHandler> handler_;
+ FilePath src_;
+ FilePath dest_;
+ friend class base::RefCountedThreadSafe<TaskProxy>;
+ DISALLOW_COPY_AND_ASSIGN(TaskProxy);
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// FileBrowseHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+FileBrowseUIHTMLSource::FileBrowseUIHTMLSource()
+ : DataSource(chrome::kChromeUIFileBrowseHost, MessageLoop::current()) {
+}
+
+void FileBrowseUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ // TODO(dhg): Add stirings to localized strings, also add more strings
+ // that are currently hardcoded.
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_TITLE));
+ localized_strings.SetString("pause",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_PAUSE));
+ localized_strings.SetString("resume",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_RESUME));
+ localized_strings.SetString("scanning",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_SCANNING));
+ localized_strings.SetString("confirmdelete",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_DELETE));
+ localized_strings.SetString("confirmyes",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_YES));
+ localized_strings.SetString("confirmcancel",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_CANCEL));
+ localized_strings.SetString("allowdownload",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_DOWNLOAD));
+ localized_strings.SetString("filenameprompt",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_PROMPT_FILENAME));
+ localized_strings.SetString("save",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_SAVE));
+ localized_strings.SetString("newfolder",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_NEW_FOLDER));
+ localized_strings.SetString("open",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_OPEN));
+ localized_strings.SetString("picasaweb",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_UPLOAD_PICASAWEB));
+ localized_strings.SetString("flickr",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_UPLOAD_FLICKR));
+ localized_strings.SetString("email",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_UPLOAD_EMAIL));
+ localized_strings.SetString("delete",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_DELETE));
+ localized_strings.SetString("enqueue",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_ENQUEUE));
+ localized_strings.SetString("mediapath", kMediaPath);
+ FilePath default_download_path;
+ if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
+ &default_download_path)) {
+ NOTREACHED();
+ }
+ // TODO(viettrungluu): this is wrong -- FilePath's need not be Unicode.
+ localized_strings.SetString("downloadpath", default_download_path.value());
+ localized_strings.SetString("error_unknown_file_type",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_ERROR_UNKNOWN_FILE_TYPE));
+ SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece filebrowse_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_FILEBROWSE_HTML));
+ const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
+ filebrowse_html, &localized_strings);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// FilebrowseHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+FilebrowseHandler::FilebrowseHandler()
+ : profile_(NULL),
+ tab_contents_(NULL),
+ is_refresh_(false),
+ fetch_(NULL),
+ download_manager_(NULL),
+ got_first_download_list_(false) {
+ lister_ = NULL;
+#if defined(OS_CHROMEOS)
+ chromeos::MountLibrary* lib =
+ chromeos::CrosLibrary::Get()->GetMountLibrary();
+ lib->AddObserver(this);
+#endif
+}
+
+FilebrowseHandler::~FilebrowseHandler() {
+#if defined(OS_CHROMEOS)
+ chromeos::MountLibrary* lib =
+ chromeos::CrosLibrary::Get()->GetMountLibrary();
+ lib->RemoveObserver(this);
+#endif
+ if (lister_.get()) {
+ lister_->Cancel();
+ lister_->set_delegate(NULL);
+ }
+
+ ClearDownloadItems();
+ download_manager_->RemoveObserver(this);
+ URLFetcher* fetch = fetch_.release();
+ if (fetch) {
+ scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), currentpath_);
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ task.get(), &TaskProxy::DeleteFetcher, fetch));
+ }
+}
+
+WebUIMessageHandler* FilebrowseHandler::Attach(WebUI* web_ui) {
+ // Create our favicon data source.
+ profile_ = web_ui->GetProfile();
+ profile_->GetChromeURLDataManager()->AddDataSource(
+ new FavIconSource(profile_));
+ tab_contents_ = web_ui->tab_contents();
+ return WebUIMessageHandler::Attach(web_ui);
+}
+
+void FilebrowseHandler::Init() {
+ download_manager_ = profile_->GetDownloadManager();
+ download_manager_->AddObserver(this);
+ static bool sent_request = false;
+ if (!sent_request) {
+ // If we have not sent a request before, we should do one in order to
+ // ensure that we have the correct cookies. This is for uploads.
+ scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), currentpath_);
+ current_task_ = task;
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ task.get(), &TaskProxy::SendPicasawebRequestProxy));
+ sent_request = true;
+ }
+}
+
+void FilebrowseHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("getRoots",
+ NewCallback(this, &FilebrowseHandler::HandleGetRoots));
+ web_ui_->RegisterMessageCallback("getChildren",
+ NewCallback(this, &FilebrowseHandler::HandleGetChildren));
+ web_ui_->RegisterMessageCallback("getMetadata",
+ NewCallback(this, &FilebrowseHandler::HandleGetMetadata));
+ web_ui_->RegisterMessageCallback("openNewPopupWindow",
+ NewCallback(this, &FilebrowseHandler::OpenNewPopupWindow));
+ web_ui_->RegisterMessageCallback("openNewFullWindow",
+ NewCallback(this, &FilebrowseHandler::OpenNewFullWindow));
+ web_ui_->RegisterMessageCallback("uploadToPicasaweb",
+ NewCallback(this, &FilebrowseHandler::UploadToPicasaweb));
+ web_ui_->RegisterMessageCallback("getDownloads",
+ NewCallback(this, &FilebrowseHandler::HandleGetDownloads));
+ web_ui_->RegisterMessageCallback("createNewFolder",
+ NewCallback(this, &FilebrowseHandler::HandleCreateNewFolder));
+ web_ui_->RegisterMessageCallback("playMediaFile",
+ NewCallback(this, &FilebrowseHandler::PlayMediaFile));
+ web_ui_->RegisterMessageCallback("enqueueMediaFile",
+ NewCallback(this, &FilebrowseHandler::EnqueueMediaFile));
+ web_ui_->RegisterMessageCallback("pauseToggleDownload",
+ NewCallback(this, &FilebrowseHandler::HandlePauseToggleDownload));
+ web_ui_->RegisterMessageCallback("deleteFile",
+ NewCallback(this, &FilebrowseHandler::HandleDeleteFile));
+ web_ui_->RegisterMessageCallback("copyFile",
+ NewCallback(this, &FilebrowseHandler::HandleCopyFile));
+ web_ui_->RegisterMessageCallback("cancelDownload",
+ NewCallback(this, &FilebrowseHandler::HandleCancelDownload));
+ web_ui_->RegisterMessageCallback("allowDownload",
+ NewCallback(this, &FilebrowseHandler::HandleAllowDownload));
+ web_ui_->RegisterMessageCallback("refreshDirectory",
+ NewCallback(this, &FilebrowseHandler::HandleRefreshDirectory));
+ web_ui_->RegisterMessageCallback("isAdvancedEnabled",
+ NewCallback(this, &FilebrowseHandler::HandleIsAdvancedEnabled));
+ web_ui_->RegisterMessageCallback("validateSavePath",
+ NewCallback(this, &FilebrowseHandler::HandleValidateSavePath));
+}
+
+
+void FilebrowseHandler::FireDeleteComplete(const FilePath& path) {
+ // We notify the UI by telling it to refresh its contents.
+ FilePath dir_path = path.DirName();
+ GetChildrenForPath(dir_path, true);
+};
+
+void FilebrowseHandler::FireCopyComplete(const FilePath& src,
+ const FilePath& dest) {
+ // Notify the UI somehow.
+ FilePath dir_path = dest.DirName();
+ GetChildrenForPath(dir_path, true);
+};
+
+void FilebrowseHandler::FireUploadComplete() {
+#if defined(OS_CHROMEOS)
+ DictionaryValue info_value;
+ info_value.SetString("path", current_file_uploaded_);
+
+ std::string username;
+ chromeos::UserManager* user_man = chromeos::UserManager::Get();
+ username = user_man->logged_in_user().email();
+
+ if (username.empty()) {
+ LOG(ERROR) << "Unable to get username";
+ return;
+ }
+ int location = username.find_first_of('@', 0);
+ if (location <= 0) {
+ LOG(ERROR) << "Username not formatted correctly";
+ return;
+ }
+ username = username.erase(username.find_first_of('@', 0));
+ std::string picture_url = kPicasawebBaseUrl;
+ picture_url += username;
+ picture_url += kPicasawebDropBox;
+ info_value.SetString("url", picture_url);
+ info_value.SetInteger("status_code", upload_response_code_);
+ web_ui_->CallJavascriptFunction(L"uploadComplete", info_value);
+#endif
+}
+
+#if defined(OS_CHROMEOS)
+void FilebrowseHandler::MountChanged(chromeos::MountLibrary* obj,
+ chromeos::MountEventType evt,
+ const std::string& path) {
+ if (evt == chromeos::DISK_REMOVED ||
+ evt == chromeos::DISK_CHANGED) {
+ web_ui_->CallJavascriptFunction(L"rootsChanged");
+ }
+}
+#endif
+
+void FilebrowseHandler::OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const net::URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ upload_response_code_ = response_code;
+ VLOG(1) << "Response code: " << response_code;
+ VLOG(1) << "Request url: " << url;
+ if (StartsWithASCII(url.spec(), kPicasawebUserPrefix, true)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(current_task_, &TaskProxy::FireUploadCompleteProxy));
+ }
+ fetch_.reset();
+}
+
+void FilebrowseHandler::HandleGetRoots(const ListValue* args) {
+ ListValue results_value;
+ DictionaryValue info_value;
+ // TODO(dhg): add other entries, make this more general
+#if defined(OS_CHROMEOS)
+ chromeos::MountLibrary* lib =
+ chromeos::CrosLibrary::Get()->GetMountLibrary();
+ const chromeos::MountLibrary::DiskVector& disks = lib->disks();
+
+ for (size_t i = 0; i < disks.size(); ++i) {
+ if (!disks[i].mount_path.empty()) {
+ DictionaryValue* page_value = new DictionaryValue();
+ page_value->SetString(kPropertyPath, disks[i].mount_path);
+ FilePath currentpath(disks[i].mount_path);
+ std::string filename;
+ filename = currentpath.BaseName().value();
+ page_value->SetString(kPropertyTitle, filename);
+ page_value->SetBoolean(kPropertyDirectory, true);
+ results_value.Append(page_value);
+ }
+ }
+#else
+ DictionaryValue* page_value = new DictionaryValue();
+ page_value->SetString(kPropertyPath, "/media");
+ page_value->SetString(kPropertyTitle, "Removeable");
+ page_value->SetBoolean(kPropertyDirectory, true);
+ results_value.Append(page_value);
+#endif
+ FilePath default_download_path;
+ if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
+ &default_download_path)) {
+ NOTREACHED();
+ }
+
+ DictionaryValue* download_value = new DictionaryValue();
+ download_value->SetString(kPropertyPath, default_download_path.value());
+ download_value->SetString(kPropertyTitle, "File Shelf");
+ download_value->SetBoolean(kPropertyDirectory, true);
+
+ results_value.Append(download_value);
+
+ info_value.SetString("functionCall", "getRoots");
+ info_value.SetString(kPropertyPath, "");
+ web_ui_->CallJavascriptFunction(L"browseFileResult",
+ info_value, results_value);
+}
+
+void FilebrowseHandler::HandleCreateNewFolder(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ FilePath currentpath(path);
+
+ scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), currentpath);
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ task.get(), &TaskProxy::CreateNewFolderProxy));
+#endif
+}
+
+void FilebrowseHandler::CreateNewFolder(const FilePath& currentpath) const {
+ if (!ValidateSaveDir(currentpath, false) ||
+ !file_util::CreateDirectory(currentpath))
+ LOG(ERROR) << "Unable to create directory " << currentpath.value();
+}
+
+void FilebrowseHandler::PlayMediaFile(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string url = WideToUTF8(ExtractStringValue(args));
+ GURL gurl(url);
+
+ Browser* browser = Browser::GetBrowserForController(
+ &tab_contents_->controller(), NULL);
+ MediaPlayer* mediaplayer = MediaPlayer::GetInstance();
+ mediaplayer->ForcePlayMediaURL(gurl, browser);
+#endif
+}
+
+void FilebrowseHandler::EnqueueMediaFile(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string url = WideToUTF8(ExtractStringValue(args));
+ GURL gurl(url);
+
+ Browser* browser = Browser::GetBrowserForController(
+ &tab_contents_->controller(), NULL);
+ MediaPlayer* mediaplayer = MediaPlayer::GetInstance();
+ mediaplayer->EnqueueMediaURL(gurl, browser);
+#endif
+}
+
+void FilebrowseHandler::HandleIsAdvancedEnabled(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ bool is_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableAdvancedFileSystem);
+ bool mp_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableMediaPlayer);
+ DictionaryValue info_value;
+ info_value.SetBoolean("enabled", is_enabled);
+ info_value.SetBoolean("mpEnabled", mp_enabled);
+ web_ui_->CallJavascriptFunction(L"enabledResult",
+ info_value);
+
+#endif
+}
+
+void FilebrowseHandler::HandleRefreshDirectory(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ FilePath currentpath(path);
+ GetChildrenForPath(currentpath, true);
+#endif
+}
+
+void FilebrowseHandler::HandlePauseToggleDownload(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ int id;
+ ExtractIntegerValue(args, &id);
+ if ((id - 1) >= static_cast<int>(active_download_items_.size())) {
+ return;
+ }
+ DownloadItem* item = active_download_items_[id];
+ item->TogglePause();
+#endif
+}
+
+void FilebrowseHandler::HandleAllowDownload(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ int id;
+ ExtractIntegerValue(args, &id);
+ if ((id - 1) >= static_cast<int>(active_download_items_.size())) {
+ return;
+ }
+
+ DownloadItem* item = active_download_items_[id];
+ download_manager_->DangerousDownloadValidated(item);
+#endif
+}
+
+void FilebrowseHandler::HandleCancelDownload(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ int id;
+ ExtractIntegerValue(args, &id);
+ if ((id - 1) >= static_cast<int>(active_download_items_.size())) {
+ return;
+ }
+ DownloadItem* item = active_download_items_[id];
+ FilePath path = item->full_path();
+ item->Cancel(true);
+ FilePath dir_path = path.DirName();
+ item->Remove(true);
+ GetChildrenForPath(dir_path, true);
+#endif
+}
+
+void FilebrowseHandler::OpenNewFullWindow(const ListValue* args) {
+ OpenNewWindow(args, false);
+}
+
+void FilebrowseHandler::OpenNewPopupWindow(const ListValue* args) {
+ OpenNewWindow(args, true);
+}
+
+void FilebrowseHandler::OpenNewWindow(const ListValue* args, bool popup) {
+ std::string url = WideToUTF8(ExtractStringValue(args));
+ Browser* browser = popup ?
+ Browser::CreateForType(Browser::TYPE_APP_PANEL, profile_) :
+ BrowserList::GetLastActive();
+ browser::NavigateParams params(browser, GURL(url), PageTransition::LINK);
+ params.disposition = NEW_FOREGROUND_TAB;
+ browser::Navigate(&params);
+ // TODO(beng): The following two calls should be automatic by Navigate().
+ if (popup) {
+ // TODO(dhg): Remove these from being hardcoded. Allow javascript
+ // to specify.
+ params.browser->window()->SetBounds(gfx::Rect(0, 0, 400, 300));
+ }
+ params.browser->window()->Show();
+}
+
+void FilebrowseHandler::SendPicasawebRequest() {
+#if defined(OS_CHROMEOS)
+ chromeos::UserManager* user_man = chromeos::UserManager::Get();
+ std::string username = user_man->logged_in_user().email();
+
+ if (username.empty()) {
+ LOG(ERROR) << "Unable to get username";
+ return;
+ }
+
+ fetch_.reset(URLFetcher::Create(0,
+ GURL(kPicasawebBaseUrl),
+ URLFetcher::GET,
+ this));
+ fetch_->set_request_context(profile_->GetRequestContext());
+ fetch_->Start();
+#endif
+}
+
+void FilebrowseHandler::ReadInFile() {
+#if defined(OS_CHROMEOS)
+ // Get the users username
+ std::string username;
+ chromeos::UserManager* user_man = chromeos::UserManager::Get();
+ username = user_man->logged_in_user().email();
+
+ if (username.empty()) {
+ LOG(ERROR) << "Unable to get username";
+ return;
+ }
+ int location = username.find_first_of('@', 0);
+ if (location <= 0) {
+ LOG(ERROR) << "Username not formatted correctly";
+ return;
+ }
+ username = username.erase(username.find_first_of('@', 0));
+ std::string url = kPicasawebUserPrefix;
+ url += username;
+ url += kPicasawebDefault;
+
+ FilePath currentpath(current_file_uploaded_);
+ // Get the filename
+ std::string filename;
+ filename = currentpath.BaseName().value();
+ std::string filecontents;
+ if (!file_util::ReadFileToString(currentpath, &filecontents)) {
+ LOG(ERROR) << "Unable to read this file:" << currentpath.value();
+ return;
+ }
+ fetch_.reset(URLFetcher::Create(0,
+ GURL(url),
+ URLFetcher::POST,
+ this));
+ fetch_->set_upload_data("image/jpeg", filecontents);
+ // Set the filename on the server
+ std::string slug = "Slug: ";
+ slug += filename;
+ fetch_->set_extra_request_headers(slug);
+ fetch_->set_request_context(profile_->GetRequestContext());
+ fetch_->Start();
+#endif
+}
+
+// This is just a prototype for allowing generic uploads to various sites
+// TODO(dhg): Remove this and implement general upload.
+void FilebrowseHandler::UploadToPicasaweb(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string search_string = WideToUTF8(ExtractStringValue(args));
+ current_file_uploaded_ = search_string;
+ // ReadInFile();
+ FilePath current_path(search_string);
+ scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), current_path);
+ current_task_ = task;
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ task.get(), &TaskProxy::ReadInFileProxy));
+#endif
+}
+
+void FilebrowseHandler::GetChildrenForPath(const FilePath& path,
+ bool is_refresh) {
+ if (path.empty())
+ return;
+
+ filelist_value_.reset(new ListValue());
+ currentpath_ = path;
+
+ if (lister_.get()) {
+ lister_->Cancel();
+ lister_->set_delegate(NULL);
+ lister_ = NULL;
+ }
+
+ is_refresh_ = is_refresh;
+
+#if defined(OS_CHROMEOS)
+ // Don't allow listing files in inaccessible dirs.
+ if (AccessDisabled(path))
+ return;
+#endif
+
+ FilePath default_download_path;
+ if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
+ &default_download_path)) {
+ NOTREACHED();
+ }
+
+ if (currentpath_ == default_download_path) {
+ lister_ = new net::DirectoryLister(currentpath_,
+ false,
+ net::DirectoryLister::DATE,
+ this);
+ } else {
+ lister_ = new net::DirectoryLister(currentpath_, this);
+ }
+ lister_->Start();
+}
+
+void FilebrowseHandler::HandleGetChildren(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ FilePath currentpath(path);
+ filelist_value_.reset(new ListValue());
+
+ GetChildrenForPath(currentpath, false);
+#endif
+}
+
+void FilebrowseHandler::OnListFile(
+ const net::DirectoryLister::DirectoryListerData& data) {
+#if defined(OS_WIN)
+ if (data.info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
+ return;
+ }
+#elif defined(OS_POSIX)
+ if (data.info.filename[0] == '.') {
+ return;
+ }
+
+ // Suppress .crdownload files.
+ static const char crdownload[] = (".crdownload");
+ static const size_t crdownload_size = arraysize(crdownload);
+ const std::string& filename = data.info.filename;
+ if ((filename.size() > crdownload_size) &&
+ (filename.rfind(crdownload) == (filename.size() - crdownload_size)))
+ return;
+#endif
+
+ DictionaryValue* file_value = new DictionaryValue();
+
+#if defined(OS_WIN)
+ int64 size = (static_cast<int64>(data.info.nFileSizeHigh) << 32) |
+ data.info.nFileSizeLow;
+ file_value->SetString(kPropertyTitle, data.info.cFileName);
+ file_value->SetString(kPropertyPath,
+ currentpath_.Append(data.info.cFileName).value());
+ file_value->SetBoolean(kPropertyDirectory,
+ (data.info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false);
+#elif defined(OS_POSIX)
+ file_value->SetString(kPropertyTitle, data.info.filename);
+ file_value->SetString(kPropertyPath,
+ currentpath_.Append(data.info.filename).value());
+ file_value->SetBoolean(kPropertyDirectory, S_ISDIR(data.info.stat.st_mode));
+#endif
+ filelist_value_->Append(file_value);
+}
+
+void FilebrowseHandler::OnListDone(int error) {
+ DictionaryValue info_value;
+ if (is_refresh_) {
+ info_value.SetString("functionCall", "refresh");
+ } else {
+ info_value.SetString("functionCall", "getChildren");
+ }
+ info_value.SetString(kPropertyPath, currentpath_.value());
+ web_ui_->CallJavascriptFunction(L"browseFileResult",
+ info_value, *(filelist_value_.get()));
+}
+
+void FilebrowseHandler::HandleGetMetadata(const ListValue* args) {
+}
+
+void FilebrowseHandler::HandleGetDownloads(const ListValue* args) {
+ UpdateDownloadList();
+}
+
+void FilebrowseHandler::ModelChanged() {
+ if (!currentpath_.empty())
+ GetChildrenForPath(currentpath_, true);
+ else
+ UpdateDownloadList();
+}
+
+void FilebrowseHandler::UpdateDownloadList() {
+ ClearDownloadItems();
+
+ std::vector<DownloadItem*> downloads;
+ download_manager_->GetAllDownloads(FilePath(), &downloads);
+
+ std::vector<DownloadItem*> new_downloads;
+ // Scan for any in progress downloads and add ourself to them as an observer.
+ for (DownloadList::iterator it = downloads.begin();
+ it != downloads.end(); ++it) {
+ DownloadItem* download = *it;
+ // We want to know what happens as the download progresses and be notified
+ // when the user validates the dangerous download.
+ if (download->state() == DownloadItem::IN_PROGRESS ||
+ download->safety_state() == DownloadItem::DANGEROUS) {
+ download->AddObserver(this);
+ active_download_items_.push_back(download);
+ }
+ DownloadList::iterator item = find(download_items_.begin(),
+ download_items_.end(),
+ download);
+ if (item == download_items_.end() && got_first_download_list_) {
+ SendNewDownload(download);
+ }
+ new_downloads.push_back(download);
+ }
+ download_items_.swap(new_downloads);
+ got_first_download_list_ = true;
+ SendCurrentDownloads();
+}
+
+void FilebrowseHandler::SendNewDownload(DownloadItem* download) {
+ ListValue results_value;
+ results_value.Append(download_util::CreateDownloadItemValue(download, -1));
+ web_ui_->CallJavascriptFunction(L"newDownload", results_value);
+}
+
+void FilebrowseHandler::DeleteFile(const FilePath& path, TaskProxy* task) {
+ if (!file_util::Delete(path, true)) {
+ LOG(ERROR) << "unable to delete directory";
+ }
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(task, &TaskProxy::FireDeleteCompleteProxy));
+}
+
+void FilebrowseHandler::CopyFile(const FilePath& src,
+ const FilePath& dest,
+ TaskProxy* task) {
+ if (file_util::DirectoryExists(src)) {
+ if (!file_util::CopyDirectory(src, dest, true)) {
+ LOG(ERROR) << "unable to copy directory:" << src.value();
+ }
+ } else {
+ if (!file_util::CopyFile(src, dest)) {
+ LOG(ERROR) << "unable to copy file" << src.value();
+ }
+ }
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(task, &TaskProxy::FireCopyCompleteProxy));
+}
+
+void FilebrowseHandler::HandleDeleteFile(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ FilePath currentpath(path);
+
+ // Don't allow file deletion in inaccessible dirs.
+ if (AccessDisabled(currentpath))
+ return;
+
+ for (unsigned int x = 0; x < active_download_items_.size(); x++) {
+ FilePath item = active_download_items_[x]->full_path();
+ if (item == currentpath) {
+ active_download_items_[x]->Cancel(true);
+ active_download_items_[x]->Remove(true);
+ FilePath dir_path = item.DirName();
+ GetChildrenForPath(dir_path, true);
+ return;
+ }
+ }
+ scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), currentpath);
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ task.get(), &TaskProxy::DeleteFileProxy));
+#endif
+}
+
+void FilebrowseHandler::HandleCopyFile(const ListValue* value) {
+#if defined(OS_CHROMEOS)
+ if (value && value->GetType() == Value::TYPE_LIST) {
+ const ListValue* list_value = static_cast<const ListValue*>(value);
+ std::string src;
+ std::string dest;
+
+ // Get path string.
+ if (list_value->GetString(0, &src) &&
+ list_value->GetString(1, &dest)) {
+ FilePath SrcPath = FilePath(src);
+ FilePath DestPath = FilePath(dest);
+
+ // Don't allow file copy to inaccessible dirs.
+ if (AccessDisabled(DestPath))
+ return;
+
+ scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(),
+ SrcPath, DestPath);
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ task.get(), &TaskProxy::CopyFileProxy));
+ } else {
+ LOG(ERROR) << "Unable to get string";
+ return;
+ }
+ }
+#endif
+}
+
+void FilebrowseHandler::HandleValidateSavePath(const ListValue* args) {
+ std::string string_path;
+ if (!args || !args->GetString(0, &string_path)) {
+ FireOnValidatedSavePathOnUIThread(false, FilePath()); // Invalid save path.
+ return;
+ }
+
+ FilePath save_path(string_path);
+
+#if defined(OS_CHROMEOS)
+ scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), save_path);
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(task.get(), &TaskProxy::ValidateSavePathOnFileThread));
+#else
+ // No save path checking for non-ChromeOS platforms.
+ FireOnValidatedSavePathOnUIThread(true, save_path);
+#endif
+}
+
+void FilebrowseHandler::ValidateSavePathOnFileThread(
+ const FilePath& save_path, TaskProxy* task) {
+#if defined(OS_CHROMEOS)
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ const bool valid = ValidateSaveDir(save_path.DirName(), true);
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(task,
+ &TaskProxy::FireOnValidatedSavePathOnUIThread,
+ valid));
+#endif
+}
+
+bool FilebrowseHandler::ValidateSaveDir(const FilePath& save_dir,
+ bool exists) const {
+#if defined(OS_CHROMEOS)
+ FilePath default_download_path;
+ if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
+ &default_download_path)) {
+ NOTREACHED();
+ }
+
+ // Valid save dir must be inside default download dir.
+ if (default_download_path == save_dir)
+ return true;
+ if (exists) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ return file_util::ContainsPath(default_download_path, save_dir);
+ } else {
+ return default_download_path.IsParent(save_dir);
+ }
+#endif
+ return false;
+}
+
+void FilebrowseHandler::FireOnValidatedSavePathOnUIThread(bool valid,
+ const FilePath& save_path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ FundamentalValue valid_value(valid);
+ StringValue path_value(save_path.value());
+ web_ui_->CallJavascriptFunction(L"onValidatedSavePath",
+ valid_value, path_value);
+}
+
+void FilebrowseHandler::OnDownloadUpdated(DownloadItem* download) {
+ DownloadList::iterator it = find(active_download_items_.begin(),
+ active_download_items_.end(),
+ download);
+ if (it == active_download_items_.end())
+ return;
+ const int id = static_cast<int>(it - active_download_items_.begin());
+
+ scoped_ptr<DictionaryValue> download_item(
+ download_util::CreateDownloadItemValue(download, id));
+ web_ui_->CallJavascriptFunction(L"downloadUpdated", *download_item.get());
+}
+
+void FilebrowseHandler::ClearDownloadItems() {
+ for (DownloadList::iterator it = active_download_items_.begin();
+ it != active_download_items_.end(); ++it) {
+ (*it)->RemoveObserver(this);
+ }
+ active_download_items_.clear();
+}
+
+void FilebrowseHandler::SendCurrentDownloads() {
+ ListValue results_value;
+ for (DownloadList::iterator it = active_download_items_.begin();
+ it != active_download_items_.end(); ++it) {
+ int index = static_cast<int>(it - active_download_items_.begin());
+ results_value.Append(download_util::CreateDownloadItemValue(*it, index));
+ }
+
+ web_ui_->CallJavascriptFunction(L"downloadsList", results_value);
+}
+
+void FilebrowseHandler::OnDownloadFileCompleted(DownloadItem* download) {
+ GetChildrenForPath(currentpath_, true);
+}
+
+bool FilebrowseHandler::AccessDisabled(const FilePath& path) const {
+ return !ValidateSaveDir(path, false) &&
+ net::URLRequestFileJob::AccessDisabled(path);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// FileBrowseUI
+//
+////////////////////////////////////////////////////////////////////////////////
+
+FileBrowseUI::FileBrowseUI(TabContents* contents) : HtmlDialogUI(contents) {
+ FilebrowseHandler* handler = new FilebrowseHandler();
+ AddMessageHandler((handler)->Attach(this));
+ handler->Init();
+ FileBrowseUIHTMLSource* html_source = new FileBrowseUIHTMLSource();
+
+ // Set up the chrome://filebrowse/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+// static
+Browser* FileBrowseUI::OpenPopup(Profile* profile,
+ const std::string& hashArgument,
+ int width,
+ int height) {
+ // Get existing pop up for given hashArgument.
+ Browser* browser = GetPopupForPath(hashArgument, profile);
+
+ // Create new browser if no matching pop up found.
+ if (browser == NULL) {
+ browser = Browser::CreateForType(Browser::TYPE_APP_PANEL, profile);
+ std::string url;
+ if (hashArgument.empty()) {
+ url = chrome::kChromeUIFileBrowseURL;
+ } else {
+ url = kFilebrowseURLHash;
+ url.append(hashArgument);
+ }
+
+ browser::NavigateParams params(browser, GURL(url), PageTransition::LINK);
+ params.disposition = NEW_FOREGROUND_TAB;
+ browser::Navigate(&params);
+ // TODO(beng): The following two calls should be automatic by Navigate().
+ params.browser->window()->SetBounds(gfx::Rect(kPopupLeft,
+ kPopupTop,
+ width,
+ height));
+
+ params.browser->window()->Show();
+ } else {
+ browser->window()->Show();
+ }
+
+ return browser;
+}
+
+Browser* FileBrowseUI::GetPopupForPath(const std::string& path,
+ Profile* profile) {
+ std::string current_path = path;
+ if (current_path.empty()) {
+ bool is_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableAdvancedFileSystem);
+ if (!is_enabled) {
+ FilePath default_download_path;
+ if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
+ &default_download_path)) {
+ NOTREACHED();
+ }
+ current_path = default_download_path.value();
+ }
+ }
+
+ for (BrowserList::const_iterator it = BrowserList::begin();
+ it != BrowserList::end(); ++it) {
+ if (((*it)->type() == Browser::TYPE_APP_PANEL)) {
+ TabContents* tab_contents = (*it)->GetSelectedTabContents();
+ DCHECK(tab_contents);
+ if (!tab_contents)
+ continue;
+ const GURL& url = tab_contents->GetURL();
+
+ if (url.SchemeIs(chrome::kChromeUIScheme) &&
+ url.host() == chrome::kChromeUIFileBrowseHost &&
+ url.ref() == current_path &&
+ (*it)->profile() == profile) {
+ return (*it);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+const int FileBrowseUI::kPopupWidth = 250;
+const int FileBrowseUI::kPopupHeight = 300;
+const int FileBrowseUI::kSmallPopupWidth = 250;
+const int FileBrowseUI::kSmallPopupHeight = 50;
diff --git a/chrome/browser/ui/webui/filebrowse_ui.h b/chrome/browser/ui/webui/filebrowse_ui.h
new file mode 100644
index 0000000..1df17d4
--- /dev/null
+++ b/chrome/browser/ui/webui/filebrowse_ui.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_FILEBROWSE_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_FILEBROWSE_UI_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "net/base/directory_lister.h"
+
+class Browser;
+class Profile;
+
+class FileBrowseUI : public HtmlDialogUI {
+ public:
+ static const int kPopupWidth;
+ static const int kPopupHeight;
+ static const int kSmallPopupWidth;
+ static const int kSmallPopupHeight;
+
+ explicit FileBrowseUI(TabContents* contents);
+
+ static Browser* OpenPopup(Profile* profile,
+ const std::string& hashArgument,
+ int width,
+ int height);
+ static Browser* GetPopupForPath(const std::string& path,
+ Profile* profile);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FileBrowseUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_FILEBROWSE_UI_H_
diff --git a/chrome/browser/ui/webui/flags_ui.cc b/chrome/browser/ui/webui/flags_ui.cc
new file mode 100644
index 0000000..8724388
--- /dev/null
+++ b/chrome/browser/ui/webui/flags_ui.cc
@@ -0,0 +1,204 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/flags_ui.h"
+
+#include <string>
+
+#include "base/singleton.h"
+#include "base/values.h"
+#include "chrome/browser/about_flags.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// FlagsUIHTMLSource
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class FlagsUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ FlagsUIHTMLSource()
+ : DataSource(chrome::kChromeUIFlagsHost, MessageLoop::current()) {}
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ ~FlagsUIHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(FlagsUIHTMLSource);
+};
+
+void FlagsUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ // Strings used in the JsTemplate file.
+ DictionaryValue localized_strings;
+ localized_strings.SetString("flagsLongTitle",
+ l10n_util::GetStringUTF16(IDS_FLAGS_LONG_TITLE));
+ localized_strings.SetString("flagsTableTitle",
+ l10n_util::GetStringUTF16(IDS_FLAGS_TABLE_TITLE));
+ localized_strings.SetString("flagsNoExperimentsAvailable",
+ l10n_util::GetStringUTF16(IDS_FLAGS_NO_EXPERIMENTS_AVAILABLE));
+ localized_strings.SetString("flagsWarningHeader", l10n_util::GetStringUTF16(
+ IDS_FLAGS_WARNING_HEADER));
+ localized_strings.SetString("flagsBlurb", l10n_util::GetStringUTF16(
+ IDS_FLAGS_WARNING_TEXT));
+ localized_strings.SetString("flagsRestartNotice", l10n_util::GetStringFUTF16(
+ IDS_FLAGS_RELAUNCH_NOTICE,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ localized_strings.SetString("flagsRestartButton",
+ l10n_util::GetStringUTF16(IDS_FLAGS_RELAUNCH_BUTTON));
+ localized_strings.SetString("disable",
+ l10n_util::GetStringUTF16(IDS_FLAGS_DISABLE));
+ localized_strings.SetString("enable",
+ l10n_util::GetStringUTF16(IDS_FLAGS_ENABLE));
+
+ ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece flags_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_FLAGS_HTML));
+ std::string full_html(flags_html.data(), flags_html.size());
+ jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
+ jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
+ jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
+ jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// FlagsDOMHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// The handler for Javascript messages for the about:flags page.
+class FlagsDOMHandler : public WebUIMessageHandler {
+ public:
+ FlagsDOMHandler() {}
+ virtual ~FlagsDOMHandler() {}
+
+ // WebUIMessageHandler implementation.
+ virtual void RegisterMessages();
+
+ // Callback for the "requestFlagsExperiments" message.
+ void HandleRequestFlagsExperiments(const ListValue* args);
+
+ // Callback for the "enableFlagsExperiment" message.
+ void HandleEnableFlagsExperimentMessage(const ListValue* args);
+
+ // Callback for the "restartBrowser" message. Restores all tabs on restart.
+ void HandleRestartBrowser(const ListValue* args);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FlagsDOMHandler);
+};
+
+void FlagsDOMHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("requestFlagsExperiments",
+ NewCallback(this, &FlagsDOMHandler::HandleRequestFlagsExperiments));
+ web_ui_->RegisterMessageCallback("enableFlagsExperiment",
+ NewCallback(this, &FlagsDOMHandler::HandleEnableFlagsExperimentMessage));
+ web_ui_->RegisterMessageCallback("restartBrowser",
+ NewCallback(this, &FlagsDOMHandler::HandleRestartBrowser));
+}
+
+void FlagsDOMHandler::HandleRequestFlagsExperiments(const ListValue* args) {
+ DictionaryValue results;
+ results.Set("flagsExperiments",
+ about_flags::GetFlagsExperimentsData(
+ g_browser_process->local_state()));
+ results.SetBoolean("needsRestart",
+ about_flags::IsRestartNeededToCommitChanges());
+ web_ui_->CallJavascriptFunction(L"returnFlagsExperiments", results);
+}
+
+void FlagsDOMHandler::HandleEnableFlagsExperimentMessage(
+ const ListValue* args) {
+ DCHECK_EQ(2u, args->GetSize());
+ if (args->GetSize() != 2)
+ return;
+
+ std::string experiment_internal_name;
+ std::string enable_str;
+ if (!args->GetString(0, &experiment_internal_name) ||
+ !args->GetString(1, &enable_str))
+ return;
+
+ about_flags::SetExperimentEnabled(
+ g_browser_process->local_state(),
+ experiment_internal_name,
+ enable_str == "true");
+}
+
+void FlagsDOMHandler::HandleRestartBrowser(const ListValue* args) {
+#if !defined(OS_CHROMEOS)
+ // Set the flag to restore state after the restart.
+ PrefService* pref_service = g_browser_process->local_state();
+ pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true);
+ BrowserList::CloseAllBrowsersAndExit();
+#else
+ // For CrOS instead of browser restart (which is not supported) perform a full
+ // sign out. Session will be only restored is user has that setting set.
+ // Same session restore behavior happens in case of full restart after update.
+ BrowserList::GetLastActive()->Exit();
+#endif
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// FlagsUI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+FlagsUI::FlagsUI(TabContents* contents) : WebUI(contents) {
+ AddMessageHandler((new FlagsDOMHandler())->Attach(this));
+
+ FlagsUIHTMLSource* html_source = new FlagsUIHTMLSource();
+
+ // Set up the about:flags source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+// static
+RefCountedMemory* FlagsUI::GetFaviconResourceBytes() {
+ return ResourceBundle::GetSharedInstance().
+ LoadDataResourceBytes(IDR_FLAGS);
+}
+
+// static
+void FlagsUI::RegisterPrefs(PrefService* prefs) {
+ prefs->RegisterListPref(prefs::kEnabledLabsExperiments);
+}
diff --git a/chrome/browser/ui/webui/flags_ui.h b/chrome/browser/ui/webui/flags_ui.h
new file mode 100644
index 0000000..97c5fec
--- /dev/null
+++ b/chrome/browser/ui/webui/flags_ui.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_FLAGS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_FLAGS_UI_H_
+#pragma once
+
+#include "content/browser/webui/web_ui.h"
+
+class PrefService;
+class RefCountedMemory;
+
+class FlagsUI : public WebUI {
+ public:
+ explicit FlagsUI(TabContents* contents);
+
+ static RefCountedMemory* GetFaviconResourceBytes();
+ static void RegisterPrefs(PrefService* prefs);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FlagsUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_FLAGS_UI_H_
diff --git a/chrome/browser/ui/webui/gpu_internals_ui.cc b/chrome/browser/ui/webui/gpu_internals_ui.cc
new file mode 100644
index 0000000..69cc2b7
--- /dev/null
+++ b/chrome/browser/ui/webui/gpu_internals_ui.cc
@@ -0,0 +1,405 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/gpu_internals_ui.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/singleton.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/gpu_data_manager.h"
+#include "chrome/browser/gpu_process_host.h"
+#include "chrome/browser/gpu_process_host_ui_shim.h"
+#include "chrome/browser/io_thread.h"
+#include "chrome/browser/net/chrome_net_log.h"
+#include "chrome/browser/net/connection_tester.h"
+#include "chrome/browser/net/passive_log_collector.h"
+#include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
+#include "net/base/escape.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+class GpuHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ GpuHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const;
+
+ private:
+ ~GpuHTMLSource() {}
+ DISALLOW_COPY_AND_ASSIGN(GpuHTMLSource);
+};
+
+// This class receives javascript messages from the renderer.
+// Note that the WebUI infrastructure runs on the UI thread, therefore all of
+// this class's methods are expected to run on the UI thread.
+class GpuMessageHandler
+ : public WebUIMessageHandler,
+ public base::SupportsWeakPtr<GpuMessageHandler> {
+ public:
+ GpuMessageHandler();
+ virtual ~GpuMessageHandler();
+
+ // WebUIMessageHandler implementation.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+ virtual void RegisterMessages();
+
+ // Mesages
+ void OnCallAsync(const ListValue* list);
+ void OnRequestGpuInfo(const ListValue* list);
+
+ // Submessages dispatched from OnCallAsync
+ Value* OnRequestClientInfo(const ListValue* list);
+ Value* OnRequestLogMessages(const ListValue* list);
+
+ // GPUInfo collected callback.
+ void OnGpuInfoCollected();
+
+ // Executes the javascript function |function_name| in the renderer, passing
+ // it the argument |value|.
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value* value);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler);
+
+ // Cache the Singleton for efficiency.
+ GpuDataManager* gpu_data_manager_;
+
+ Callback0::Type* gpu_info_update_callback_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// GpuHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+GpuHTMLSource::GpuHTMLSource()
+ : DataSource(chrome::kChromeUIGpuInternalsHost, MessageLoop::current()) {
+}
+
+void GpuHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ SetFontAndTextDirection(&localized_strings);
+
+ base::StringPiece gpu_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_GPU_INTERNALS_HTML));
+ std::string full_html(gpu_html.data(), gpu_html.size());
+ jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
+ jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
+ jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
+ jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
+
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+std::string GpuHTMLSource::GetMimeType(const std::string&) const {
+ return "text/html";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// GpuMessageHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+GpuMessageHandler::GpuMessageHandler() : gpu_info_update_callback_(NULL) {
+ gpu_data_manager_ = GpuDataManager::GetInstance();
+ DCHECK(gpu_data_manager_);
+}
+
+GpuMessageHandler::~GpuMessageHandler() {
+ if (gpu_info_update_callback_) {
+ gpu_data_manager_->RemoveGpuInfoUpdateCallback(gpu_info_update_callback_);
+ delete gpu_info_update_callback_;
+ }
+}
+
+WebUIMessageHandler* GpuMessageHandler::Attach(WebUI* web_ui) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui);
+ return result;
+}
+
+/* BrowserBridge.callAsync prepends a requestID to these messages. */
+void GpuMessageHandler::RegisterMessages() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ web_ui_->RegisterMessageCallback(
+ "callAsync",
+ NewCallback(this, &GpuMessageHandler::OnCallAsync));
+ web_ui_->RegisterMessageCallback(
+ "requestGpuInfo",
+ NewCallback(this, &GpuMessageHandler::OnRequestGpuInfo));
+}
+
+void GpuMessageHandler::OnCallAsync(const ListValue* args) {
+ DCHECK_GE(args->GetSize(), static_cast<size_t>(2));
+ // unpack args into requestId, submessage and submessageArgs
+ bool ok;
+ Value* requestId;
+ ok = args->Get(0, &requestId);
+ DCHECK(ok);
+
+ std::string submessage;
+ ok = args->GetString(1, &submessage);
+ DCHECK(ok);
+
+ ListValue* submessageArgs = new ListValue();
+ for (size_t i = 2; i < args->GetSize(); ++i) {
+ Value* arg;
+ ok = args->Get(i, &arg);
+ DCHECK(ok);
+
+ Value* argCopy = arg->DeepCopy();
+ submessageArgs->Append(argCopy);
+ }
+
+ // call the submessage handler
+ Value* ret = NULL;
+ if (submessage == "requestClientInfo") {
+ ret = OnRequestClientInfo(submessageArgs);
+ } else if (submessage == "requestLogMessages") {
+ ret = OnRequestLogMessages(submessageArgs);
+ } else { // unrecognized submessage
+ NOTREACHED();
+ delete submessageArgs;
+ return;
+ }
+ delete submessageArgs;
+
+ // call BrowserBridge.onCallAsyncReply with result
+ if (ret) {
+ web_ui_->CallJavascriptFunction(L"browserBridge.onCallAsyncReply",
+ *requestId,
+ *ret);
+ delete ret;
+ } else {
+ web_ui_->CallJavascriptFunction(L"browserBridge.onCallAsyncReply",
+ *requestId);
+ }
+}
+
+void GpuMessageHandler::OnRequestGpuInfo(const ListValue* args) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (gpu_info_update_callback_ == NULL) {
+ // Add us to be called when GPUInfo changes and ask for updated GPUInfo.
+ gpu_info_update_callback_ =
+ NewCallback(this, &GpuMessageHandler::OnGpuInfoCollected);
+ gpu_data_manager_->AddGpuInfoUpdateCallback(gpu_info_update_callback_);
+ // Run callback immediately in case the info is ready and no update in the
+ // future.
+ OnGpuInfoCollected();
+ }
+ GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::GetForRenderer(0);
+ if (ui_shim)
+ ui_shim->CollectGpuInfoAsynchronously(GPUInfo::kComplete);
+}
+
+Value* GpuMessageHandler::OnRequestClientInfo(const ListValue* list) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ DictionaryValue* dict = new DictionaryValue();
+
+ chrome::VersionInfo version_info;
+
+ if (!version_info.is_valid()) {
+ DLOG(ERROR) << "Unable to create chrome::VersionInfo";
+ } else {
+ // We have everything we need to send the right values.
+ dict->SetString("version", version_info.Version());
+ dict->SetString("cl", version_info.LastChange());
+ dict->SetString("version_mod",
+ platform_util::GetVersionStringModifier());
+ dict->SetString("official",
+ l10n_util::GetStringUTF16(
+ version_info.IsOfficialBuild() ?
+ IDS_ABOUT_VERSION_OFFICIAL
+ : IDS_ABOUT_VERSION_UNOFFICIAL));
+
+ dict->SetString("command_line",
+ CommandLine::ForCurrentProcess()->command_line_string());
+ }
+
+ return dict;
+}
+
+DictionaryValue* NewDescriptionValuePair(const std::string& desc,
+ const std::string& value) {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("description", desc);
+ dict->SetString("value", value);
+ return dict;
+}
+
+DictionaryValue* NewDescriptionValuePair(const std::string& desc,
+ Value* value) {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("description", desc);
+ dict->Set("value", value);
+ return dict;
+}
+
+#if defined(OS_WIN)
+// Output DxDiagNode tree as nested array of {description,value} pairs
+ListValue* DxDiagNodeToList(const DxDiagNode& node) {
+ ListValue* list = new ListValue();
+ for (std::map<std::string, std::string>::const_iterator it =
+ node.values.begin();
+ it != node.values.end();
+ ++it) {
+ list->Append(NewDescriptionValuePair(it->first, it->second));
+ }
+
+ for (std::map<std::string, DxDiagNode>::const_iterator it =
+ node.children.begin();
+ it != node.children.end();
+ ++it) {
+ ListValue* sublist = DxDiagNodeToList(it->second);
+ list->Append(NewDescriptionValuePair(it->first, sublist));
+ }
+ return list;
+}
+
+#endif // OS_WIN
+
+std::string VersionNumberToString(uint32 value) {
+ int hi = (value >> 8) & 0xff;
+ int low = value & 0xff;
+ return base::IntToString(hi) + "." + base::IntToString(low);
+}
+
+DictionaryValue* GpuInfoToDict(const GPUInfo& gpu_info) {
+ ListValue* basic_info = new ListValue();
+ basic_info->Append(NewDescriptionValuePair("Initialization time",
+ base::Int64ToString(gpu_info.initialization_time().InMilliseconds())));
+ basic_info->Append(NewDescriptionValuePair("Vendor Id",
+ base::StringPrintf("0x%04x", gpu_info.vendor_id())));
+ basic_info->Append(NewDescriptionValuePair("Device Id",
+ base::StringPrintf("0x%04x", gpu_info.device_id())));
+ basic_info->Append(NewDescriptionValuePair("Driver vendor",
+ gpu_info.driver_vendor()));
+ basic_info->Append(NewDescriptionValuePair("Driver version",
+ gpu_info.driver_version()));
+ basic_info->Append(NewDescriptionValuePair("Pixel shader version",
+ VersionNumberToString(gpu_info.pixel_shader_version())));
+ basic_info->Append(NewDescriptionValuePair("Vertex shader version",
+ VersionNumberToString(gpu_info.vertex_shader_version())));
+ basic_info->Append(NewDescriptionValuePair("GL version",
+ VersionNumberToString(gpu_info.gl_version())));
+ basic_info->Append(NewDescriptionValuePair("GL_VENDOR",
+ gpu_info.gl_vendor()));
+ basic_info->Append(NewDescriptionValuePair("GL_RENDERER",
+ gpu_info.gl_renderer()));
+ basic_info->Append(NewDescriptionValuePair("GL_VERSION",
+ gpu_info.gl_version_string()));
+ basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS",
+ gpu_info.gl_extensions()));
+
+ DictionaryValue* info = new DictionaryValue();
+ info->Set("basic_info", basic_info);
+
+ if (gpu_info.level() == GPUInfo::kPartial) {
+ info->SetString("level", "partial");
+ } else if (gpu_info.level() == GPUInfo::kCompleting) {
+ info->SetString("level", "completing");
+ } else if (gpu_info.level() == GPUInfo::kComplete) {
+ info->SetString("level", "complete");
+ } else {
+ DCHECK(false) << "Unrecognized GPUInfo::Level value";
+ info->SetString("level", "");
+ }
+
+#if defined(OS_WIN)
+ if (gpu_info.level() == GPUInfo::kComplete) {
+ ListValue* dx_info = DxDiagNodeToList(gpu_info.dx_diagnostics());
+ info->Set("diagnostics", dx_info);
+ }
+#endif
+
+ return info;
+}
+
+Value* GpuMessageHandler::OnRequestLogMessages(const ListValue*) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::GetForRenderer(0);
+ if (!ui_shim)
+ return NULL;
+
+ return ui_shim->log_messages();
+}
+
+void GpuMessageHandler::OnGpuInfoCollected() {
+ // Get GPU Info.
+ const GPUInfo& gpu_info = gpu_data_manager_->gpu_info();
+
+ if (gpu_info.level() == GPUInfo::kUninitialized)
+ return;
+
+ // Send GPU Info to javascript.
+ Value* gpuInfoVal = GpuInfoToDict(gpu_info);
+ web_ui_->CallJavascriptFunction(L"browserBridge.onGpuInfoUpdated",
+ *gpuInfoVal);
+
+ delete gpuInfoVal;
+}
+
+} // namespace
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// GpuInternalsUI
+//
+////////////////////////////////////////////////////////////////////////////////
+
+GpuInternalsUI::GpuInternalsUI(TabContents* contents) : WebUI(contents) {
+ AddMessageHandler((new GpuMessageHandler())->Attach(this));
+
+ GpuHTMLSource* html_source = new GpuHTMLSource();
+
+ // Set up the chrome://gpu/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
diff --git a/chrome/browser/ui/webui/gpu_internals_ui.h b/chrome/browser/ui/webui/gpu_internals_ui.h
new file mode 100644
index 0000000..5e7d841
--- /dev/null
+++ b/chrome/browser/ui/webui/gpu_internals_ui.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_GPU_INTERNALS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_GPU_INTERNALS_UI_H_
+#pragma once
+
+#include "content/browser/webui/web_ui.h"
+
+class GpuInternalsUI : public WebUI {
+ public:
+ explicit GpuInternalsUI(TabContents* contents);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GpuInternalsUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_GPU_INTERNALS_UI_H_
+
diff --git a/chrome/browser/ui/webui/history2_ui.cc b/chrome/browser/ui/webui/history2_ui.cc
new file mode 100644
index 0000000..fcdce94
--- /dev/null
+++ b/chrome/browser/ui/webui/history2_ui.cc
@@ -0,0 +1,413 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/history2_ui.h"
+
+#include <algorithm>
+#include <set>
+
+#include "base/callback.h"
+#include "base/i18n/time_formatting.h"
+#include "base/message_loop.h"
+#include "base/singleton.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/threading/thread.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/webui/favicon_source.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/time_format.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
+#include "net/base/escape.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+// Maximum number of search results to return in a given search. We should
+// eventually remove this.
+static const int kMaxSearchResults = 100;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// HistoryHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+HistoryUIHTMLSource2::HistoryUIHTMLSource2()
+ : DataSource(chrome::kChromeUIHistory2Host, MessageLoop::current()) {
+}
+
+void HistoryUIHTMLSource2::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ localized_strings.SetString("loading",
+ l10n_util::GetStringUTF16(IDS_HISTORY_LOADING));
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_HISTORY_TITLE));
+ localized_strings.SetString("loading",
+ l10n_util::GetStringUTF16(IDS_HISTORY_LOADING));
+ localized_strings.SetString("newest",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NEWEST));
+ localized_strings.SetString("newer",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NEWER));
+ localized_strings.SetString("older",
+ l10n_util::GetStringUTF16(IDS_HISTORY_OLDER));
+ localized_strings.SetString("searchresultsfor",
+ l10n_util::GetStringUTF16(IDS_HISTORY_SEARCHRESULTSFOR));
+ localized_strings.SetString("history",
+ l10n_util::GetStringUTF16(IDS_HISTORY_BROWSERESULTS));
+ localized_strings.SetString("cont",
+ l10n_util::GetStringUTF16(IDS_HISTORY_CONTINUED));
+ localized_strings.SetString("searchbutton",
+ l10n_util::GetStringUTF16(IDS_HISTORY_SEARCH_BUTTON));
+ localized_strings.SetString("noresults",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NO_RESULTS));
+ localized_strings.SetString("noitems",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NO_ITEMS));
+ localized_strings.SetString("edithistory",
+ l10n_util::GetStringUTF16(IDS_HISTORY_START_EDITING_HISTORY));
+ localized_strings.SetString("doneediting",
+ l10n_util::GetStringUTF16(IDS_HISTORY_STOP_EDITING_HISTORY));
+ localized_strings.SetString("removeselected",
+ l10n_util::GetStringUTF16(IDS_HISTORY_REMOVE_SELECTED_ITEMS));
+ localized_strings.SetString("clearallhistory",
+ l10n_util::GetStringUTF16(IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG));
+ localized_strings.SetString("deletewarning",
+ l10n_util::GetStringUTF16(IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING));
+
+ SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece history_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_HISTORY2_HTML));
+ const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
+ history_html, &localized_strings);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+std::string HistoryUIHTMLSource2::GetMimeType(const std::string&) const {
+ return "text/html";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// HistoryHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+BrowsingHistoryHandler2::BrowsingHistoryHandler2()
+ : search_text_() {
+}
+
+BrowsingHistoryHandler2::~BrowsingHistoryHandler2() {
+ cancelable_search_consumer_.CancelAllRequests();
+ cancelable_delete_consumer_.CancelAllRequests();
+}
+
+WebUIMessageHandler* BrowsingHistoryHandler2::Attach(WebUI* web_ui) {
+ // Create our favicon data source.
+ Profile* profile = web_ui->GetProfile();
+ profile->GetChromeURLDataManager()->AddDataSource(
+ new FavIconSource(profile));
+
+ // Get notifications when history is cleared.
+ registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
+ Source<Profile>(web_ui->GetProfile()->GetOriginalProfile()));
+ return WebUIMessageHandler::Attach(web_ui);
+}
+
+void BrowsingHistoryHandler2::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("getHistory",
+ NewCallback(this, &BrowsingHistoryHandler2::HandleGetHistory));
+ web_ui_->RegisterMessageCallback("searchHistory",
+ NewCallback(this, &BrowsingHistoryHandler2::HandleSearchHistory));
+ web_ui_->RegisterMessageCallback("removeURLsOnOneDay",
+ NewCallback(this, &BrowsingHistoryHandler2::HandleRemoveURLsOnOneDay));
+ web_ui_->RegisterMessageCallback("clearBrowsingData",
+ NewCallback(this, &BrowsingHistoryHandler2::HandleClearBrowsingData));
+}
+
+void BrowsingHistoryHandler2::HandleGetHistory(const ListValue* args) {
+ // Anything in-flight is invalid.
+ cancelable_search_consumer_.CancelAllRequests();
+
+ // Get arguments (if any).
+ int day = 0;
+ ExtractIntegerValue(args, &day);
+
+ // Set our query options.
+ history::QueryOptions options;
+ options.begin_time = base::Time::Now().LocalMidnight();
+ options.begin_time -= base::TimeDelta::FromDays(day);
+ options.end_time = base::Time::Now().LocalMidnight();
+ options.end_time -= base::TimeDelta::FromDays(day - 1);
+
+ // Need to remember the query string for our results.
+ search_text_ = string16();
+
+ HistoryService* hs =
+ web_ui_->GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->QueryHistory(search_text_,
+ options,
+ &cancelable_search_consumer_,
+ NewCallback(this, &BrowsingHistoryHandler2::QueryComplete));
+}
+
+void BrowsingHistoryHandler2::HandleSearchHistory(const ListValue* args) {
+ // Anything in-flight is invalid.
+ cancelable_search_consumer_.CancelAllRequests();
+
+ // Get arguments (if any).
+ int month = 0;
+ string16 query;
+ ExtractSearchHistoryArguments(args, &month, &query);
+
+ // Set the query ranges for the given month.
+ history::QueryOptions options = CreateMonthQueryOptions(month);
+
+ // When searching, limit the number of results returned.
+ options.max_count = kMaxSearchResults;
+
+ // Need to remember the query string for our results.
+ search_text_ = query;
+ HistoryService* hs =
+ web_ui_->GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->QueryHistory(search_text_,
+ options,
+ &cancelable_search_consumer_,
+ NewCallback(this, &BrowsingHistoryHandler2::QueryComplete));
+}
+
+void BrowsingHistoryHandler2::HandleRemoveURLsOnOneDay(const ListValue* args) {
+ if (cancelable_delete_consumer_.HasPendingRequests()) {
+ web_ui_->CallJavascriptFunction(L"deleteFailed");
+ return;
+ }
+
+ // Get day to delete data from.
+ int visit_time = 0;
+ ExtractIntegerValue(args, &visit_time);
+ base::Time::Exploded exploded;
+ base::Time::FromTimeT(
+ static_cast<time_t>(visit_time)).LocalExplode(&exploded);
+ exploded.hour = exploded.minute = exploded.second = exploded.millisecond = 0;
+ base::Time begin_time = base::Time::FromLocalExploded(exploded);
+ base::Time end_time = begin_time + base::TimeDelta::FromDays(1);
+
+ // Get URLs.
+ std::set<GURL> urls;
+ for (ListValue::const_iterator v = args->begin() + 1;
+ v != args->end(); ++v) {
+ if ((*v)->GetType() != Value::TYPE_STRING)
+ continue;
+ const StringValue* string_value = static_cast<const StringValue*>(*v);
+ string16 string16_value;
+ if (!string_value->GetAsString(&string16_value))
+ continue;
+ urls.insert(GURL(string16_value));
+ }
+
+ HistoryService* hs =
+ web_ui_->GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->ExpireHistoryBetween(
+ urls, begin_time, end_time, &cancelable_delete_consumer_,
+ NewCallback(this, &BrowsingHistoryHandler2::RemoveComplete));
+}
+
+void BrowsingHistoryHandler2::HandleClearBrowsingData(const ListValue* args) {
+ // TODO(beng): This is an improper direct dependency on Browser. Route this
+ // through some sort of delegate.
+ Browser* browser = BrowserList::FindBrowserWithProfile(web_ui_->GetProfile());
+ if (browser)
+ browser->OpenClearBrowsingDataDialog();
+}
+
+void BrowsingHistoryHandler2::QueryComplete(
+ HistoryService::Handle request_handle,
+ history::QueryResults* results) {
+
+ ListValue results_value;
+ base::Time midnight_today = base::Time::Now().LocalMidnight();
+
+ for (size_t i = 0; i < results->size(); ++i) {
+ history::URLResult const &page = (*results)[i];
+ DictionaryValue* page_value = new DictionaryValue();
+ SetURLAndTitle(page_value, page.title(), page.url());
+
+ // Need to pass the time in epoch time (fastest JS conversion).
+ page_value->SetInteger("time",
+ static_cast<int>(page.visit_time().ToTimeT()));
+
+ // Until we get some JS i18n infrastructure, we also need to
+ // pass the dates in as strings. This could use some
+ // optimization.
+
+ // Only pass in the strings we need (search results need a shortdate
+ // and snippet, browse results need day and time information).
+ if (search_text_.empty()) {
+ // Figure out the relative date string.
+ string16 date_str = TimeFormat::RelativeDate(page.visit_time(),
+ &midnight_today);
+ if (date_str.empty()) {
+ date_str = base::TimeFormatFriendlyDate(page.visit_time());
+ } else {
+ date_str = l10n_util::GetStringFUTF16(
+ IDS_HISTORY_DATE_WITH_RELATIVE_TIME,
+ date_str,
+ base::TimeFormatFriendlyDate(page.visit_time()));
+ }
+ page_value->SetString("dateRelativeDay", date_str);
+ page_value->SetString("dateTimeOfDay",
+ base::TimeFormatTimeOfDay(page.visit_time()));
+ } else {
+ page_value->SetString("dateShort",
+ base::TimeFormatShortDate(page.visit_time()));
+ page_value->SetString("snippet", page.snippet().text());
+ }
+ page_value->SetBoolean("starred",
+ web_ui_->GetProfile()->GetBookmarkModel()->IsBookmarked(page.url()));
+ results_value.Append(page_value);
+ }
+
+ DictionaryValue info_value;
+ info_value.SetString("term", search_text_);
+ info_value.SetBoolean("finished", results->reached_beginning());
+
+ web_ui_->CallJavascriptFunction(L"historyResult", info_value, results_value);
+}
+
+void BrowsingHistoryHandler2::RemoveComplete() {
+ // Some Visits were deleted from history. Reload the list.
+ web_ui_->CallJavascriptFunction(L"deleteComplete");
+}
+
+void BrowsingHistoryHandler2::ExtractSearchHistoryArguments(
+ const ListValue* args,
+ int* month,
+ string16* query) {
+ *month = 0;
+ Value* list_member;
+
+ // Get search string.
+ if (args->Get(0, &list_member) &&
+ list_member->GetType() == Value::TYPE_STRING) {
+ const StringValue* string_value =
+ static_cast<const StringValue*>(list_member);
+ string_value->GetAsString(query);
+ }
+
+ // Get search month.
+ if (args->Get(1, &list_member) &&
+ list_member->GetType() == Value::TYPE_STRING) {
+ const StringValue* string_value =
+ static_cast<const StringValue*>(list_member);
+ string16 string16_value;
+ string_value->GetAsString(&string16_value);
+ base::StringToInt(string16_value, month);
+ }
+}
+
+history::QueryOptions BrowsingHistoryHandler2::CreateMonthQueryOptions(
+ int month) {
+ history::QueryOptions options;
+
+ // Configure the begin point of the search to the start of the
+ // current month.
+ base::Time::Exploded exploded;
+ base::Time::Now().LocalMidnight().LocalExplode(&exploded);
+ exploded.day_of_month = 1;
+
+ if (month == 0) {
+ options.begin_time = base::Time::FromLocalExploded(exploded);
+
+ // Set the end time of this first search to null (which will
+ // show results from the future, should the user's clock have
+ // been set incorrectly).
+ options.end_time = base::Time();
+ } else {
+ // Set the end-time of this search to the end of the month that is
+ // |depth| months before the search end point. The end time is not
+ // inclusive, so we should feel free to set it to midnight on the
+ // first day of the following month.
+ exploded.month -= month - 1;
+ while (exploded.month < 1) {
+ exploded.month += 12;
+ exploded.year--;
+ }
+ options.end_time = base::Time::FromLocalExploded(exploded);
+
+ // Set the begin-time of the search to the start of the month
+ // that is |depth| months prior to search_start_.
+ if (exploded.month > 1) {
+ exploded.month--;
+ } else {
+ exploded.month = 12;
+ exploded.year--;
+ }
+ options.begin_time = base::Time::FromLocalExploded(exploded);
+ }
+
+ return options;
+}
+
+void BrowsingHistoryHandler2::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type != NotificationType::HISTORY_URLS_DELETED) {
+ NOTREACHED();
+ return;
+ }
+
+ // Some URLs were deleted from history. Reload the list.
+ web_ui_->CallJavascriptFunction(L"historyDeleted");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// HistoryUIContents
+//
+////////////////////////////////////////////////////////////////////////////////
+
+HistoryUI2::HistoryUI2(TabContents* contents) : WebUI(contents) {
+ AddMessageHandler((new BrowsingHistoryHandler2())->Attach(this));
+
+ HistoryUIHTMLSource2* html_source = new HistoryUIHTMLSource2();
+
+ // Set up the chrome://history2/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+// static
+const GURL HistoryUI2::GetHistoryURLWithSearchText(const string16& text) {
+ return GURL(std::string(chrome::kChromeUIHistory2URL) + "#q=" +
+ EscapeQueryParamValue(UTF16ToUTF8(text), true));
+}
+
+// static
+RefCountedMemory* HistoryUI2::GetFaviconResourceBytes() {
+ return ResourceBundle::GetSharedInstance().
+ LoadDataResourceBytes(IDR_HISTORY_FAVICON);
+}
diff --git a/chrome/browser/ui/webui/history2_ui.h b/chrome/browser/ui/webui/history2_ui.h
new file mode 100644
index 0000000..cf99253
--- /dev/null
+++ b/chrome/browser/ui/webui/history2_ui.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_HISTORY2_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_HISTORY2_UI_H_
+#pragma once
+
+#include <string>
+
+#include "base/string16.h"
+#include "chrome/browser/cancelable_request.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/notification_registrar.h"
+#include "content/browser/webui/web_ui.h"
+
+class GURL;
+
+// Temporary fork for development of new history UI.
+// TODO(pamg): merge back in when new UI is complete.
+
+class HistoryUIHTMLSource2 : public ChromeURLDataManager::DataSource {
+ public:
+ HistoryUIHTMLSource2();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+
+ virtual std::string GetMimeType(const std::string&) const;
+
+ private:
+ ~HistoryUIHTMLSource2() {}
+
+ DISALLOW_COPY_AND_ASSIGN(HistoryUIHTMLSource2);
+};
+
+// The handler for Javascript messages related to the "history" view.
+class BrowsingHistoryHandler2 : public WebUIMessageHandler,
+ public NotificationObserver {
+ public:
+ BrowsingHistoryHandler2();
+ virtual ~BrowsingHistoryHandler2();
+
+ // WebUIMessageHandler implementation.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+ virtual void RegisterMessages();
+
+ // Callback for the "getHistory" message.
+ void HandleGetHistory(const ListValue* args);
+
+ // Callback for the "searchHistory" message.
+ void HandleSearchHistory(const ListValue* args);
+
+ // Callback for the "removeURLsOnOneDay" message.
+ void HandleRemoveURLsOnOneDay(const ListValue* args);
+
+ // Handle for "clearBrowsingData" message.
+ void HandleClearBrowsingData(const ListValue* args);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // Callback from the history system when the history list is available.
+ void QueryComplete(HistoryService::Handle request_handle,
+ history::QueryResults* results);
+
+ // Callback from the history system when visits were deleted.
+ void RemoveComplete();
+
+ // Extract the arguments from the call to HandleSearchHistory.
+ void ExtractSearchHistoryArguments(const ListValue* args,
+ int* month,
+ string16* query);
+
+ // Figure out the query options for a month-wide query.
+ history::QueryOptions CreateMonthQueryOptions(int month);
+
+ NotificationRegistrar registrar_;
+
+ // Current search text.
+ string16 search_text_;
+
+ // Our consumer for search requests to the history service.
+ CancelableRequestConsumerT<int, 0> cancelable_search_consumer_;
+
+ // Our consumer for delete requests to the history service.
+ CancelableRequestConsumerT<int, 0> cancelable_delete_consumer_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowsingHistoryHandler2);
+};
+
+class HistoryUI2 : public WebUI {
+ public:
+ explicit HistoryUI2(TabContents* contents);
+
+ // Return the URL for a given search term.
+ static const GURL GetHistoryURLWithSearchText(const string16& text);
+
+ static RefCountedMemory* GetFaviconResourceBytes();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HistoryUI2);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_HISTORY2_UI_H_
diff --git a/chrome/browser/ui/webui/history_ui.cc b/chrome/browser/ui/webui/history_ui.cc
new file mode 100644
index 0000000..5cc50da8
--- /dev/null
+++ b/chrome/browser/ui/webui/history_ui.cc
@@ -0,0 +1,401 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/history_ui.h"
+
+#include <algorithm>
+#include <set>
+
+#include "base/callback.h"
+#include "base/i18n/time_formatting.h"
+#include "base/message_loop.h"
+#include "base/singleton.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/threading/thread.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/webui/favicon_source.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/time_format.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
+#include "net/base/escape.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+// Maximum number of search results to return in a given search. We should
+// eventually remove this.
+static const int kMaxSearchResults = 100;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// HistoryHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+HistoryUIHTMLSource::HistoryUIHTMLSource()
+ : DataSource(chrome::kChromeUIHistoryHost, MessageLoop::current()) {
+}
+
+void HistoryUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ localized_strings.SetString("loading",
+ l10n_util::GetStringUTF16(IDS_HISTORY_LOADING));
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_HISTORY_TITLE));
+ localized_strings.SetString("loading",
+ l10n_util::GetStringUTF16(IDS_HISTORY_LOADING));
+ localized_strings.SetString("newest",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NEWEST));
+ localized_strings.SetString("newer",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NEWER));
+ localized_strings.SetString("older",
+ l10n_util::GetStringUTF16(IDS_HISTORY_OLDER));
+ localized_strings.SetString("searchresultsfor",
+ l10n_util::GetStringUTF16(IDS_HISTORY_SEARCHRESULTSFOR));
+ localized_strings.SetString("history",
+ l10n_util::GetStringUTF16(IDS_HISTORY_BROWSERESULTS));
+ localized_strings.SetString("cont",
+ l10n_util::GetStringUTF16(IDS_HISTORY_CONTINUED));
+ localized_strings.SetString("searchbutton",
+ l10n_util::GetStringUTF16(IDS_HISTORY_SEARCH_BUTTON));
+ localized_strings.SetString("noresults",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NO_RESULTS));
+ localized_strings.SetString("noitems",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NO_ITEMS));
+ localized_strings.SetString("edithistory",
+ l10n_util::GetStringUTF16(IDS_HISTORY_START_EDITING_HISTORY));
+ localized_strings.SetString("doneediting",
+ l10n_util::GetStringUTF16(IDS_HISTORY_STOP_EDITING_HISTORY));
+ localized_strings.SetString("removeselected",
+ l10n_util::GetStringUTF16(IDS_HISTORY_REMOVE_SELECTED_ITEMS));
+ localized_strings.SetString("clearallhistory",
+ l10n_util::GetStringUTF16(IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG));
+ localized_strings.SetString("deletewarning",
+ l10n_util::GetStringUTF16(IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING));
+
+ SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece history_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_HISTORY_HTML));
+ const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
+ history_html, &localized_strings);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+std::string HistoryUIHTMLSource::GetMimeType(const std::string&) const {
+ return "text/html";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// HistoryHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+BrowsingHistoryHandler::BrowsingHistoryHandler()
+ : search_text_() {
+}
+
+BrowsingHistoryHandler::~BrowsingHistoryHandler() {
+ cancelable_search_consumer_.CancelAllRequests();
+ cancelable_delete_consumer_.CancelAllRequests();
+}
+
+WebUIMessageHandler* BrowsingHistoryHandler::Attach(WebUI* web_ui) {
+ // Create our favicon data source.
+ Profile* profile = web_ui->GetProfile();
+ profile->GetChromeURLDataManager()->AddDataSource(
+ new FavIconSource(profile));
+
+ // Get notifications when history is cleared.
+ registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
+ Source<Profile>(profile->GetOriginalProfile()));
+ return WebUIMessageHandler::Attach(web_ui);
+}
+
+void BrowsingHistoryHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("getHistory",
+ NewCallback(this, &BrowsingHistoryHandler::HandleGetHistory));
+ web_ui_->RegisterMessageCallback("searchHistory",
+ NewCallback(this, &BrowsingHistoryHandler::HandleSearchHistory));
+ web_ui_->RegisterMessageCallback("removeURLsOnOneDay",
+ NewCallback(this, &BrowsingHistoryHandler::HandleRemoveURLsOnOneDay));
+ web_ui_->RegisterMessageCallback("clearBrowsingData",
+ NewCallback(this, &BrowsingHistoryHandler::HandleClearBrowsingData));
+}
+
+void BrowsingHistoryHandler::HandleGetHistory(const ListValue* args) {
+ // Anything in-flight is invalid.
+ cancelable_search_consumer_.CancelAllRequests();
+
+ // Get arguments (if any).
+ int day = 0;
+ ExtractIntegerValue(args, &day);
+
+ // Set our query options.
+ history::QueryOptions options;
+ options.begin_time = base::Time::Now().LocalMidnight();
+ options.begin_time -= base::TimeDelta::FromDays(day);
+ options.end_time = base::Time::Now().LocalMidnight();
+ options.end_time -= base::TimeDelta::FromDays(day - 1);
+
+ // Need to remember the query string for our results.
+ search_text_ = string16();
+
+ HistoryService* hs =
+ web_ui_->GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->QueryHistory(search_text_,
+ options,
+ &cancelable_search_consumer_,
+ NewCallback(this, &BrowsingHistoryHandler::QueryComplete));
+}
+
+void BrowsingHistoryHandler::HandleSearchHistory(const ListValue* args) {
+ // Anything in-flight is invalid.
+ cancelable_search_consumer_.CancelAllRequests();
+
+ // Get arguments (if any).
+ int month = 0;
+ string16 query;
+ ExtractSearchHistoryArguments(args, &month, &query);
+
+ // Set the query ranges for the given month.
+ history::QueryOptions options = CreateMonthQueryOptions(month);
+
+ // When searching, limit the number of results returned.
+ options.max_count = kMaxSearchResults;
+
+ // Need to remember the query string for our results.
+ search_text_ = query;
+ HistoryService* hs =
+ web_ui_->GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->QueryHistory(search_text_,
+ options,
+ &cancelable_search_consumer_,
+ NewCallback(this, &BrowsingHistoryHandler::QueryComplete));
+}
+
+void BrowsingHistoryHandler::HandleRemoveURLsOnOneDay(const ListValue* args) {
+ if (cancelable_delete_consumer_.HasPendingRequests()) {
+ web_ui_->CallJavascriptFunction(L"deleteFailed");
+ return;
+ }
+
+ // Get day to delete data from.
+ int visit_time = 0;
+ ExtractIntegerValue(args, &visit_time);
+ base::Time::Exploded exploded;
+ base::Time::FromTimeT(
+ static_cast<time_t>(visit_time)).LocalExplode(&exploded);
+ exploded.hour = exploded.minute = exploded.second = exploded.millisecond = 0;
+ base::Time begin_time = base::Time::FromLocalExploded(exploded);
+ base::Time end_time = begin_time + base::TimeDelta::FromDays(1);
+
+ // Get URLs.
+ std::set<GURL> urls;
+ for (ListValue::const_iterator v = args->begin() + 1;
+ v != args->end(); ++v) {
+ if ((*v)->GetType() != Value::TYPE_STRING)
+ continue;
+ const StringValue* string_value = static_cast<const StringValue*>(*v);
+ string16 string16_value;
+ if (!string_value->GetAsString(&string16_value))
+ continue;
+ urls.insert(GURL(string16_value));
+ }
+
+ HistoryService* hs =
+ web_ui_->GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->ExpireHistoryBetween(
+ urls, begin_time, end_time, &cancelable_delete_consumer_,
+ NewCallback(this, &BrowsingHistoryHandler::RemoveComplete));
+}
+
+void BrowsingHistoryHandler::HandleClearBrowsingData(const ListValue* args) {
+ // TODO(beng): This is an improper direct dependency on Browser. Route this
+ // through some sort of delegate.
+ Browser* browser = BrowserList::FindBrowserWithProfile(web_ui_->GetProfile());
+ if (browser)
+ browser->OpenClearBrowsingDataDialog();
+}
+
+void BrowsingHistoryHandler::QueryComplete(
+ HistoryService::Handle request_handle,
+ history::QueryResults* results) {
+
+ ListValue results_value;
+ base::Time midnight_today = base::Time::Now().LocalMidnight();
+
+ for (size_t i = 0; i < results->size(); ++i) {
+ history::URLResult const &page = (*results)[i];
+ DictionaryValue* page_value = new DictionaryValue();
+ SetURLAndTitle(page_value, page.title(), page.url());
+
+ // Need to pass the time in epoch time (fastest JS conversion).
+ page_value->SetInteger("time",
+ static_cast<int>(page.visit_time().ToTimeT()));
+
+ // Until we get some JS i18n infrastructure, we also need to
+ // pass the dates in as strings. This could use some
+ // optimization.
+
+ // Only pass in the strings we need (search results need a shortdate
+ // and snippet, browse results need day and time information).
+ if (search_text_.empty()) {
+ // Figure out the relative date string.
+ string16 date_str = TimeFormat::RelativeDate(page.visit_time(),
+ &midnight_today);
+ if (date_str.empty()) {
+ date_str = base::TimeFormatFriendlyDate(page.visit_time());
+ } else {
+ date_str = l10n_util::GetStringFUTF16(
+ IDS_HISTORY_DATE_WITH_RELATIVE_TIME,
+ date_str,
+ base::TimeFormatFriendlyDate(page.visit_time()));
+ }
+ page_value->SetString("dateRelativeDay", date_str);
+ page_value->SetString("dateTimeOfDay",
+ base::TimeFormatTimeOfDay(page.visit_time()));
+ } else {
+ page_value->SetString("dateShort",
+ base::TimeFormatShortDate(page.visit_time()));
+ page_value->SetString("snippet", page.snippet().text());
+ }
+ page_value->SetBoolean("starred",
+ web_ui_->GetProfile()->GetBookmarkModel()->IsBookmarked(page.url()));
+ results_value.Append(page_value);
+ }
+
+ DictionaryValue info_value;
+ info_value.SetString("term", search_text_);
+ info_value.SetBoolean("finished", results->reached_beginning());
+
+ web_ui_->CallJavascriptFunction(L"historyResult", info_value, results_value);
+}
+
+void BrowsingHistoryHandler::RemoveComplete() {
+ // Some Visits were deleted from history. Reload the list.
+ web_ui_->CallJavascriptFunction(L"deleteComplete");
+}
+
+void BrowsingHistoryHandler::ExtractSearchHistoryArguments(
+ const ListValue* args,
+ int* month,
+ string16* query) {
+ CHECK(args->GetSize() == 2);
+ query->clear();
+ CHECK(args->GetString(0, query));
+
+ string16 string16_value;
+ CHECK(args->GetString(1, &string16_value));
+ *month = 0;
+ base::StringToInt(string16_value, month);
+}
+
+history::QueryOptions BrowsingHistoryHandler::CreateMonthQueryOptions(
+ int month) {
+ history::QueryOptions options;
+
+ // Configure the begin point of the search to the start of the
+ // current month.
+ base::Time::Exploded exploded;
+ base::Time::Now().LocalMidnight().LocalExplode(&exploded);
+ exploded.day_of_month = 1;
+
+ if (month == 0) {
+ options.begin_time = base::Time::FromLocalExploded(exploded);
+
+ // Set the end time of this first search to null (which will
+ // show results from the future, should the user's clock have
+ // been set incorrectly).
+ options.end_time = base::Time();
+ } else {
+ // Set the end-time of this search to the end of the month that is
+ // |depth| months before the search end point. The end time is not
+ // inclusive, so we should feel free to set it to midnight on the
+ // first day of the following month.
+ exploded.month -= month - 1;
+ while (exploded.month < 1) {
+ exploded.month += 12;
+ exploded.year--;
+ }
+ options.end_time = base::Time::FromLocalExploded(exploded);
+
+ // Set the begin-time of the search to the start of the month
+ // that is |depth| months prior to search_start_.
+ if (exploded.month > 1) {
+ exploded.month--;
+ } else {
+ exploded.month = 12;
+ exploded.year--;
+ }
+ options.begin_time = base::Time::FromLocalExploded(exploded);
+ }
+
+ return options;
+}
+
+void BrowsingHistoryHandler::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type != NotificationType::HISTORY_URLS_DELETED) {
+ NOTREACHED();
+ return;
+ }
+
+ // Some URLs were deleted from history. Reload the list.
+ web_ui_->CallJavascriptFunction(L"historyDeleted");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// HistoryUIContents
+//
+////////////////////////////////////////////////////////////////////////////////
+
+HistoryUI::HistoryUI(TabContents* contents) : WebUI(contents) {
+ AddMessageHandler((new BrowsingHistoryHandler())->Attach(this));
+
+ HistoryUIHTMLSource* html_source = new HistoryUIHTMLSource();
+
+ // Set up the chrome://history/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+// static
+const GURL HistoryUI::GetHistoryURLWithSearchText(const string16& text) {
+ return GURL(std::string(chrome::kChromeUIHistoryURL) + "#q=" +
+ EscapeQueryParamValue(UTF16ToUTF8(text), true));
+}
+
+// static
+RefCountedMemory* HistoryUI::GetFaviconResourceBytes() {
+ return ResourceBundle::GetSharedInstance().
+ LoadDataResourceBytes(IDR_HISTORY_FAVICON);
+}
diff --git a/chrome/browser/ui/webui/history_ui.h b/chrome/browser/ui/webui/history_ui.h
new file mode 100644
index 0000000..0513fbe
--- /dev/null
+++ b/chrome/browser/ui/webui/history_ui.h
@@ -0,0 +1,108 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_HISTORY_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_HISTORY_UI_H_
+#pragma once
+
+#include <string>
+
+#include "base/string16.h"
+#include "chrome/browser/cancelable_request.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/notification_registrar.h"
+#include "content/browser/webui/web_ui.h"
+
+class GURL;
+
+class HistoryUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ HistoryUIHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const;
+
+ private:
+ ~HistoryUIHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(HistoryUIHTMLSource);
+};
+
+// The handler for Javascript messages related to the "history" view.
+class BrowsingHistoryHandler : public WebUIMessageHandler,
+ public NotificationObserver {
+ public:
+ BrowsingHistoryHandler();
+ virtual ~BrowsingHistoryHandler();
+
+ // WebUIMessageHandler implementation.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+ virtual void RegisterMessages();
+
+ // Callback for the "getHistory" message.
+ void HandleGetHistory(const ListValue* args);
+
+ // Callback for the "searchHistory" message.
+ void HandleSearchHistory(const ListValue* args);
+
+ // Callback for the "removeURLsOnOneDay" message.
+ void HandleRemoveURLsOnOneDay(const ListValue* args);
+
+ // Handle for "clearBrowsingData" message.
+ void HandleClearBrowsingData(const ListValue* args);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // Callback from the history system when the history list is available.
+ void QueryComplete(HistoryService::Handle request_handle,
+ history::QueryResults* results);
+
+ // Callback from the history system when visits were deleted.
+ void RemoveComplete();
+
+ // Extract the arguments from the call to HandleSearchHistory.
+ void ExtractSearchHistoryArguments(const ListValue* args,
+ int* month,
+ string16* query);
+
+ // Figure out the query options for a month-wide query.
+ history::QueryOptions CreateMonthQueryOptions(int month);
+
+ NotificationRegistrar registrar_;
+
+ // Current search text.
+ string16 search_text_;
+
+ // Our consumer for search requests to the history service.
+ CancelableRequestConsumerT<int, 0> cancelable_search_consumer_;
+
+ // Our consumer for delete requests to the history service.
+ CancelableRequestConsumerT<int, 0> cancelable_delete_consumer_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowsingHistoryHandler);
+};
+
+class HistoryUI : public WebUI {
+ public:
+ explicit HistoryUI(TabContents* contents);
+
+ // Return the URL for a given search term.
+ static const GURL GetHistoryURLWithSearchText(const string16& text);
+
+ static RefCountedMemory* GetFaviconResourceBytes();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HistoryUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_HISTORY_UI_H_
diff --git a/chrome/browser/ui/webui/html_dialog_ui.cc b/chrome/browser/ui/webui/html_dialog_ui.cc
new file mode 100644
index 0000000..ff07d7f
--- /dev/null
+++ b/chrome/browser/ui/webui/html_dialog_ui.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
+
+#include "base/callback.h"
+#include "base/lazy_instance.h"
+#include "base/values.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/bindings_policy.h"
+#include "content/browser/webui/web_ui_util.h"
+
+static base::LazyInstance<PropertyAccessor<HtmlDialogUIDelegate*> >
+ g_html_dialog_ui_property_accessor(base::LINKER_INITIALIZED);
+
+HtmlDialogUI::HtmlDialogUI(TabContents* tab_contents) : WebUI(tab_contents) {
+}
+
+HtmlDialogUI::~HtmlDialogUI() {
+ // Don't unregister our property. During the teardown of the TabContents,
+ // this will be deleted, but the TabContents will already be destroyed.
+ //
+ // This object is owned indirectly by the TabContents. WebUIs can change, so
+ // it's scary if this WebUI is changed out and replaced with something else,
+ // since the property will still point to the old delegate. But the delegate
+ // is itself the owner of the TabContents for a dialog so will be in scope,
+ // and the HTML dialogs won't swap WebUIs anyway since they don't navigate.
+}
+
+// static
+PropertyAccessor<HtmlDialogUIDelegate*>& HtmlDialogUI::GetPropertyAccessor() {
+ return g_html_dialog_ui_property_accessor.Get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private:
+
+void HtmlDialogUI::RenderViewCreated(RenderViewHost* render_view_host) {
+ // Hook up the javascript function calls, also known as chrome.send("foo")
+ // calls in the HTML, to the actual C++ functions.
+ RegisterMessageCallback("DialogClose",
+ NewCallback(this, &HtmlDialogUI::OnDialogClosed));
+
+ // Pass the arguments to the renderer supplied by the delegate.
+ std::string dialog_args;
+ std::vector<WebUIMessageHandler*> handlers;
+ HtmlDialogUIDelegate** delegate = GetPropertyAccessor().GetProperty(
+ tab_contents()->property_bag());
+ if (delegate) {
+ dialog_args = (*delegate)->GetDialogArgs();
+ (*delegate)->GetWebUIMessageHandlers(&handlers);
+ }
+
+ if (0 != (bindings_ & BindingsPolicy::WEB_UI))
+ render_view_host->SetWebUIProperty("dialogArguments", dialog_args);
+ for (std::vector<WebUIMessageHandler*>::iterator it = handlers.begin();
+ it != handlers.end(); ++it) {
+ (*it)->Attach(this);
+ AddMessageHandler(*it);
+ }
+}
+
+void HtmlDialogUI::OnDialogClosed(const ListValue* args) {
+ HtmlDialogUIDelegate** delegate = GetPropertyAccessor().GetProperty(
+ tab_contents()->property_bag());
+ if (delegate) {
+ (*delegate)->OnDialogClosed(
+ web_ui_util::GetJsonResponseFromFirstArgumentInList(args));
+ }
+}
+
+ExternalHtmlDialogUI::ExternalHtmlDialogUI(TabContents* tab_contents)
+ : HtmlDialogUI(tab_contents) {
+ // Non-file based UI needs to not have access to the Web UI bindings
+ // for security reasons. The code hosting the dialog should provide
+ // dialog specific functionality through other bindings and methods
+ // that are scoped in duration to the dialogs existence.
+ bindings_ &= ~BindingsPolicy::WEB_UI;
+}
+
+ExternalHtmlDialogUI::~ExternalHtmlDialogUI() {
+}
+
+bool HtmlDialogUIDelegate::HandleContextMenu(const ContextMenuParams& params) {
+ return false;
+}
diff --git a/chrome/browser/ui/webui/html_dialog_ui.h b/chrome/browser/ui/webui/html_dialog_ui.h
new file mode 100644
index 0000000..6ffa4f6
--- /dev/null
+++ b/chrome/browser/ui/webui/html_dialog_ui.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_HTML_DIALOG_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_HTML_DIALOG_UI_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "chrome/common/property_bag.h"
+#include "content/browser/webui/web_ui.h"
+#include "googleurl/src/gurl.h"
+
+namespace gfx {
+class Size;
+}
+
+struct ContextMenuParams;
+
+// Implement this class to receive notifications.
+class HtmlDialogUIDelegate {
+ public:
+ // Returns true if the contents needs to be run in a modal dialog.
+ virtual bool IsDialogModal() const = 0;
+
+ // Returns the title of the dialog.
+ virtual std::wstring GetDialogTitle() const = 0;
+
+ // Get the HTML file path for the content to load in the dialog.
+ virtual GURL GetDialogContentURL() const = 0;
+
+ // Get WebUIMessageHandler objects to handle messages from the HTML/JS page.
+ // The handlers are used to send and receive messages from the page while it
+ // is still open. Ownership of each handler is taken over by the WebUI
+ // hosting the page.
+ virtual void GetWebUIMessageHandlers(
+ std::vector<WebUIMessageHandler*>* handlers) const = 0;
+
+ // Get the size of the dialog.
+ virtual void GetDialogSize(gfx::Size* size) const = 0;
+
+ // Gets the JSON string input to use when showing the dialog.
+ virtual std::string GetDialogArgs() const = 0;
+
+ // A callback to notify the delegate that the dialog closed.
+ virtual void OnDialogClosed(const std::string& json_retval) = 0;
+
+ // A callback to notify the delegate that the contents have gone
+ // away. Only relevant if your dialog hosts code that calls
+ // windows.close() and you've allowed that. If the output parameter
+ // is set to true, then the dialog is closed. The default is false.
+ virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) = 0;
+
+ // A callback to allow the delegate to dictate that the window should not
+ // have a title bar. This is useful when presenting branded interfaces.
+ virtual bool ShouldShowDialogTitle() const = 0;
+
+ // A callback to allow the delegate to inhibit context menu or show
+ // customized menu.
+ virtual bool HandleContextMenu(const ContextMenuParams& params);
+
+ protected:
+ virtual ~HtmlDialogUIDelegate() {}
+};
+
+// Displays file URL contents inside a modal HTML dialog.
+//
+// This application really should not use TabContents + WebUI. It should instead
+// just embed a RenderView in a dialog and be done with it.
+//
+// Before loading a URL corresponding to this WebUI, the caller should set its
+// delegate as a property on the TabContents. This WebUI will pick it up from
+// there and call it back. This is a bit of a hack to allow the dialog to pass
+// its delegate to the Web UI without having nasty accessors on the TabContents.
+// The correct design using RVH directly would avoid all of this.
+class HtmlDialogUI : public WebUI {
+ public:
+ struct HtmlDialogParams {
+ // The URL for the content that will be loaded in the dialog.
+ GURL url;
+ // Width of the dialog.
+ int width;
+ // Height of the dialog.
+ int height;
+ // The JSON input to pass to the dialog when showing it.
+ std::string json_input;
+ };
+
+ // When created, the property should already be set on the TabContents.
+ explicit HtmlDialogUI(TabContents* tab_contents);
+ virtual ~HtmlDialogUI();
+
+ // Returns the PropertyBag accessor object used to write the delegate pointer
+ // into the TabContents (see class-level comment above).
+ static PropertyAccessor<HtmlDialogUIDelegate*>& GetPropertyAccessor();
+
+ private:
+ // WebUI
+ virtual void RenderViewCreated(RenderViewHost* render_view_host);
+
+ // JS message handler.
+ void OnDialogClosed(const ListValue* args);
+
+ DISALLOW_COPY_AND_ASSIGN(HtmlDialogUI);
+};
+
+// Displays external URL contents inside a modal HTML dialog.
+//
+// Intended to be the place to collect the settings and lockdowns
+// necessary for running external UI conponents securely (e.g., the
+// cloud print dialog).
+class ExternalHtmlDialogUI : public HtmlDialogUI {
+ public:
+ explicit ExternalHtmlDialogUI(TabContents* tab_contents);
+ virtual ~ExternalHtmlDialogUI();
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_HTML_DIALOG_UI_H_
diff --git a/chrome/browser/ui/webui/keyboard_ui.cc b/chrome/browser/ui/webui/keyboard_ui.cc
new file mode 100644
index 0000000..af7445c
--- /dev/null
+++ b/chrome/browser/ui/webui/keyboard_ui.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/keyboard_ui.h"
+
+#include "base/ref_counted_memory.h"
+#include "base/singleton.h"
+#include "base/string_piece.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/url_constants.h"
+#include "ui/base/resource/resource_bundle.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// KeyboardUI
+
+KeyboardUI::KeyboardUI(TabContents* contents)
+ : WebUI(contents) {
+ KeyboardHTMLSource* html_source = new KeyboardHTMLSource();
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+KeyboardUI::~KeyboardUI() {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// KeyboardHTMLSource
+
+KeyboardUI::KeyboardHTMLSource::KeyboardHTMLSource()
+ : DataSource(chrome::kChromeUIKeyboardHost, MessageLoop::current()) {
+}
+
+void KeyboardUI::KeyboardHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ NOTREACHED() << "We should never get here since the extension should have"
+ << "been triggered";
+ SendResponse(request_id, NULL);
+}
+
+std::string KeyboardUI::KeyboardHTMLSource::GetMimeType(
+ const std::string&) const {
+ NOTREACHED() << "We should never get here since the extension should have"
+ << "been triggered";
+ return "text/html";
+}
diff --git a/chrome/browser/ui/webui/keyboard_ui.h b/chrome/browser/ui/webui/keyboard_ui.h
new file mode 100644
index 0000000..980e28b
--- /dev/null
+++ b/chrome/browser/ui/webui/keyboard_ui.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_KEYBOARD_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_KEYBOARD_UI_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "content/browser/webui/web_ui.h"
+
+class Profile;
+
+// The TabContents used for the keyboard page.
+class KeyboardUI : public WebUI {
+ public:
+ explicit KeyboardUI(TabContents* manager);
+ ~KeyboardUI();
+
+ class KeyboardHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ KeyboardHTMLSource();
+
+ // Overrides from DataSource
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const;
+
+ private:
+ virtual ~KeyboardHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(KeyboardHTMLSource);
+ };
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(KeyboardUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_KEYBOARD_UI_H_
diff --git a/chrome/browser/ui/webui/mediaplayer_ui.cc b/chrome/browser/ui/webui/mediaplayer_ui.cc
new file mode 100644
index 0000000..d43930f
--- /dev/null
+++ b/chrome/browser/ui/webui/mediaplayer_ui.cc
@@ -0,0 +1,613 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/mediaplayer_ui.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/singleton.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/threading/thread.h"
+#include "base/time.h"
+#include "base/values.h"
+#include "base/weak_ptr.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/webui/favicon_source.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/net/url_fetcher.h"
+#include "chrome/common/time_format.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "net/base/escape.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_request_job.h"
+#include "ui/base/resource/resource_bundle.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/frame/panel_browser_view.h"
+#endif
+
+static const char kPropertyPath[] = "path";
+static const char kPropertyForce[] = "force";
+static const char kPropertyOffset[] = "currentOffset";
+static const char kPropertyError[] = "error";
+
+static const char* kMediaplayerURL = "chrome://mediaplayer";
+static const char* kMediaplayerPlaylistURL = "chrome://mediaplayer#playlist";
+static const int kPopupLeft = 0;
+static const int kPopupTop = 0;
+static const int kPopupWidth = 350;
+static const int kPopupHeight = 300;
+
+class MediaplayerUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ explicit MediaplayerUIHTMLSource(bool is_playlist);
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ ~MediaplayerUIHTMLSource() {}
+ bool is_playlist_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaplayerUIHTMLSource);
+};
+
+// The handler for Javascript messages related to the "mediaplayer" view.
+class MediaplayerHandler : public WebUIMessageHandler,
+ public base::SupportsWeakPtr<MediaplayerHandler> {
+ public:
+
+ struct MediaUrl {
+ MediaUrl() {}
+ explicit MediaUrl(const GURL& newurl)
+ : url(newurl),
+ haderror(false) {}
+ GURL url;
+ bool haderror;
+ };
+ typedef std::vector<MediaUrl> UrlVector;
+
+ explicit MediaplayerHandler(bool is_playlist);
+
+ virtual ~MediaplayerHandler();
+
+ // Init work after Attach.
+ void Init(bool is_playlist, TabContents* contents);
+
+ // WebUIMessageHandler implementation.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+ virtual void RegisterMessages();
+
+ // Callback for the "currentOffsetChanged" message.
+ void HandleCurrentOffsetChanged(const ListValue* args);
+
+ void FirePlaylistChanged(const std::string& path,
+ bool force,
+ int offset);
+
+ void PlaybackMediaFile(const GURL& url);
+
+ void EnqueueMediaFile(const GURL& url);
+
+ void GetPlaylistValue(ListValue& args);
+
+ // Callback for the "playbackError" message.
+ void HandlePlaybackError(const ListValue* args);
+
+ // Callback for the "getCurrentPlaylist" message.
+ void HandleGetCurrentPlaylist(const ListValue* args);
+
+ void HandleTogglePlaylist(const ListValue* args);
+ void HandleShowPlaylist(const ListValue* args);
+ void HandleSetCurrentPlaylistOffset(const ListValue* args);
+ void HandleToggleFullscreen(const ListValue* args);
+
+ const UrlVector& GetCurrentPlaylist();
+
+ int GetCurrentPlaylistOffset();
+ void SetCurrentPlaylistOffset(int offset);
+ // Sets the playlist for playlist views, since the playlist is
+ // maintained by the mediaplayer itself. Offset is the item in the
+ // playlist which is either now playing, or should be played.
+ void SetCurrentPlaylist(const UrlVector& playlist, int offset);
+
+ private:
+ // The current playlist of urls.
+ UrlVector current_playlist_;
+ // The offset into the current_playlist_ of the currently playing item.
+ int current_offset_;
+ // Indicator of if this handler is a playlist or a mediaplayer.
+ bool is_playlist_;
+ DISALLOW_COPY_AND_ASSIGN(MediaplayerHandler);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MediaplayerHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+MediaplayerUIHTMLSource::MediaplayerUIHTMLSource(bool is_playlist)
+ : DataSource(chrome::kChromeUIMediaplayerHost, MessageLoop::current()) {
+ is_playlist_ = is_playlist;
+}
+
+void MediaplayerUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ // TODO(dhg): Fix the strings that are currently hardcoded so they
+ // use the localized versions.
+ localized_strings.SetString("errorstring", "Error Playing Back");
+
+ SetFontAndTextDirection(&localized_strings);
+
+ std::string full_html;
+
+ static const base::StringPiece mediaplayer_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_MEDIAPLAYER_HTML));
+
+ static const base::StringPiece playlist_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_MEDIAPLAYERPLAYLIST_HTML));
+
+ if (is_playlist_) {
+ full_html = jstemplate_builder::GetI18nTemplateHtml(
+ playlist_html, &localized_strings);
+ } else {
+ full_html = jstemplate_builder::GetI18nTemplateHtml(
+ mediaplayer_html, &localized_strings);
+ }
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MediaplayerHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+MediaplayerHandler::MediaplayerHandler(bool is_playlist)
+ : current_offset_(0),
+ is_playlist_(is_playlist) {
+}
+
+MediaplayerHandler::~MediaplayerHandler() {
+}
+
+WebUIMessageHandler* MediaplayerHandler::Attach(WebUI* web_ui) {
+ // Create our favicon data source.
+ Profile* profile = web_ui->GetProfile();
+ profile->GetChromeURLDataManager()->AddDataSource(
+ new FavIconSource(profile));
+
+ return WebUIMessageHandler::Attach(web_ui);
+}
+
+void MediaplayerHandler::Init(bool is_playlist, TabContents* contents) {
+ MediaPlayer* player = MediaPlayer::GetInstance();
+ if (!is_playlist) {
+ player->SetNewHandler(this, contents);
+ } else {
+ player->RegisterNewPlaylistHandler(this, contents);
+ }
+}
+
+void MediaplayerHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("currentOffsetChanged",
+ NewCallback(this, &MediaplayerHandler::HandleCurrentOffsetChanged));
+ web_ui_->RegisterMessageCallback("playbackError",
+ NewCallback(this, &MediaplayerHandler::HandlePlaybackError));
+ web_ui_->RegisterMessageCallback("getCurrentPlaylist",
+ NewCallback(this, &MediaplayerHandler::HandleGetCurrentPlaylist));
+ web_ui_->RegisterMessageCallback("togglePlaylist",
+ NewCallback(this, &MediaplayerHandler::HandleTogglePlaylist));
+ web_ui_->RegisterMessageCallback("setCurrentPlaylistOffset",
+ NewCallback(this, &MediaplayerHandler::HandleSetCurrentPlaylistOffset));
+ web_ui_->RegisterMessageCallback("toggleFullscreen",
+ NewCallback(this, &MediaplayerHandler::HandleToggleFullscreen));
+ web_ui_->RegisterMessageCallback("showPlaylist",
+ NewCallback(this, &MediaplayerHandler::HandleShowPlaylist));
+}
+
+void MediaplayerHandler::GetPlaylistValue(ListValue& urls) {
+ for (size_t x = 0; x < current_playlist_.size(); x++) {
+ DictionaryValue* url_value = new DictionaryValue();
+ url_value->SetString(kPropertyPath, current_playlist_[x].url.spec());
+ url_value->SetBoolean(kPropertyError, current_playlist_[x].haderror);
+ urls.Append(url_value);
+ }
+}
+
+void MediaplayerHandler::PlaybackMediaFile(const GURL& url) {
+ current_playlist_.clear();
+ current_playlist_.push_back(MediaplayerHandler::MediaUrl(url));
+ FirePlaylistChanged(url.spec(), true, 0);
+ MediaPlayer::GetInstance()->NotifyPlaylistChanged();
+}
+
+const MediaplayerHandler::UrlVector& MediaplayerHandler::GetCurrentPlaylist() {
+ return current_playlist_;
+}
+
+int MediaplayerHandler::GetCurrentPlaylistOffset() {
+ return current_offset_;
+}
+
+void MediaplayerHandler::HandleToggleFullscreen(const ListValue* args) {
+ MediaPlayer::GetInstance()->ToggleFullscreen();
+}
+
+void MediaplayerHandler::HandleSetCurrentPlaylistOffset(const ListValue* args) {
+ int id;
+ CHECK(ExtractIntegerValue(args, &id));
+ MediaPlayer::GetInstance()->SetPlaylistOffset(id);
+}
+
+void MediaplayerHandler::FirePlaylistChanged(const std::string& path,
+ bool force,
+ int offset) {
+ DictionaryValue info_value;
+ ListValue urls;
+ GetPlaylistValue(urls);
+ info_value.SetString(kPropertyPath, path);
+ info_value.SetBoolean(kPropertyForce, force);
+ info_value.SetInteger(kPropertyOffset, offset);
+ web_ui_->CallJavascriptFunction(L"playlistChanged", info_value, urls);
+}
+
+void MediaplayerHandler::SetCurrentPlaylistOffset(int offset) {
+ current_offset_ = offset;
+ FirePlaylistChanged(std::string(), true, current_offset_);
+}
+
+void MediaplayerHandler::SetCurrentPlaylist(
+ const MediaplayerHandler::UrlVector& playlist, int offset) {
+ current_playlist_ = playlist;
+ current_offset_ = offset;
+ FirePlaylistChanged(std::string(), false, current_offset_);
+}
+
+void MediaplayerHandler::EnqueueMediaFile(const GURL& url) {
+ current_playlist_.push_back(MediaplayerHandler::MediaUrl(url));
+ FirePlaylistChanged(url.spec(), false, current_offset_);
+ MediaPlayer::GetInstance()->NotifyPlaylistChanged();
+}
+
+void MediaplayerHandler::HandleCurrentOffsetChanged(const ListValue* args) {
+ CHECK(ExtractIntegerValue(args, &current_offset_));
+ MediaPlayer::GetInstance()->NotifyPlaylistChanged();
+}
+
+void MediaplayerHandler::HandlePlaybackError(const ListValue* args) {
+ std::string error;
+ std::string url;
+ // Get path string.
+ if (args->GetString(0, &error))
+ LOG(ERROR) << "Playback error" << error;
+ if (args->GetString(1, &url)) {
+ for (size_t x = 0; x < current_playlist_.size(); x++) {
+ if (current_playlist_[x].url == GURL(url)) {
+ current_playlist_[x].haderror = true;
+ }
+ }
+ FirePlaylistChanged(std::string(), false, current_offset_);
+ }
+}
+
+void MediaplayerHandler::HandleGetCurrentPlaylist(const ListValue* args) {
+ FirePlaylistChanged(std::string(), false, current_offset_);
+}
+
+void MediaplayerHandler::HandleTogglePlaylist(const ListValue* args) {
+ MediaPlayer::GetInstance()->TogglePlaylistWindowVisible();
+}
+
+void MediaplayerHandler::HandleShowPlaylist(const ListValue* args) {
+ MediaPlayer::GetInstance()->ShowPlaylistWindow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Mediaplayer
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Allows InvokeLater without adding refcounting. This class is a Singleton and
+// won't be deleted until it's last InvokeLater is run.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(MediaPlayer);
+
+MediaPlayer::~MediaPlayer() {
+}
+
+// static
+MediaPlayer* MediaPlayer::GetInstance() {
+ return Singleton<MediaPlayer>::get();
+}
+
+void MediaPlayer::EnqueueMediaURL(const GURL& url, Browser* creator) {
+ if (!Enabled()) {
+ return;
+ }
+ if (handler_ == NULL) {
+ unhandled_urls_.push_back(url);
+ PopupMediaPlayer(creator);
+ } else {
+ handler_->EnqueueMediaFile(url);
+ }
+}
+
+void MediaPlayer::ForcePlayMediaURL(const GURL& url, Browser* creator) {
+ if (!Enabled()) {
+ return;
+ }
+ if (handler_ == NULL) {
+ unhandled_urls_.push_back(url);
+ PopupMediaPlayer(creator);
+ } else {
+ handler_->PlaybackMediaFile(url);
+ }
+}
+
+bool MediaPlayer::Enabled() {
+#if defined(OS_CHROMEOS)
+ return CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableMediaPlayer);
+#else
+ return true;
+#endif
+}
+
+void MediaPlayer::TogglePlaylistWindowVisible() {
+ if (playlist_browser_) {
+ ClosePlaylistWindow();
+ } else {
+ ShowPlaylistWindow();
+ }
+}
+
+void MediaPlayer::ShowPlaylistWindow() {
+ if (playlist_browser_ == NULL) {
+ PopupPlaylist(NULL);
+ }
+}
+
+void MediaPlayer::ClosePlaylistWindow() {
+ if (playlist_browser_ != NULL) {
+ playlist_browser_->window()->Close();
+ }
+}
+
+void MediaPlayer::SetPlaylistOffset(int offset) {
+ if (handler_) {
+ handler_->SetCurrentPlaylistOffset(offset);
+ }
+ if (playlist_) {
+ playlist_->SetCurrentPlaylistOffset(offset);
+ }
+}
+
+void MediaPlayer::SetNewHandler(MediaplayerHandler* handler,
+ TabContents* contents) {
+ handler_ = handler;
+ mediaplayer_tab_ = contents;
+ RegisterListeners();
+ for (size_t x = 0; x < unhandled_urls_.size(); x++) {
+ handler_->EnqueueMediaFile(unhandled_urls_[x]);
+ }
+ unhandled_urls_.clear();
+}
+
+void MediaPlayer::RegisterListeners() {
+ registrar_.RemoveAll();
+ if (playlist_tab_) {
+ registrar_.Add(this,
+ NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(playlist_tab_));
+ }
+ if (mediaplayer_tab_) {
+ registrar_.Add(this,
+ NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(mediaplayer_tab_));
+ }
+};
+
+void MediaPlayer::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED);
+ if (Source<TabContents>(source).ptr() == mediaplayer_tab_) {
+ RemoveHandler(handler_);
+ RegisterListeners();
+ ClosePlaylistWindow();
+ } else if (Source<TabContents>(source).ptr() == playlist_tab_) {
+ RemovePlaylistHandler(playlist_);
+ RegisterListeners();
+ }
+}
+
+void MediaPlayer::RegisterNewPlaylistHandler(MediaplayerHandler* handler,
+ TabContents* contents) {
+ playlist_ = handler;
+ playlist_tab_ = contents;
+ RegisterListeners();
+ NotifyPlaylistChanged();
+}
+
+void MediaPlayer::RemovePlaylistHandler(MediaplayerHandler* handler) {
+ if (handler == playlist_) {
+ playlist_ = NULL;
+ playlist_browser_ = NULL;
+ playlist_tab_ = NULL;
+ }
+}
+
+void MediaPlayer::NotifyPlaylistChanged() {
+ if (handler_ && playlist_) {
+ playlist_->SetCurrentPlaylist(handler_->GetCurrentPlaylist(),
+ handler_->GetCurrentPlaylistOffset());
+ }
+}
+
+void MediaPlayer::ToggleFullscreen() {
+ if (handler_ && mediaplayer_browser_) {
+ mediaplayer_browser_->ToggleFullscreenMode();
+ }
+}
+
+void MediaPlayer::RemoveHandler(MediaplayerHandler* handler) {
+ if (handler == handler_) {
+ handler_ = NULL;
+ mediaplayer_browser_ = NULL;
+ mediaplayer_tab_ = NULL;
+ }
+}
+
+void MediaPlayer::PopupPlaylist(Browser* creator) {
+ Profile* profile = BrowserList::GetLastActive()->profile();
+ playlist_browser_ = Browser::CreateForType(Browser::TYPE_APP_PANEL,
+ profile);
+ playlist_browser_->AddSelectedTabWithURL(GURL(kMediaplayerPlaylistURL),
+ PageTransition::LINK);
+ playlist_browser_->window()->SetBounds(gfx::Rect(kPopupLeft,
+ kPopupTop,
+ kPopupWidth,
+ kPopupHeight));
+ playlist_browser_->window()->Show();
+}
+
+void MediaPlayer::PopupMediaPlayer(Browser* creator) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &MediaPlayer::PopupMediaPlayer,
+ static_cast<Browser*>(NULL)));
+ return;
+ }
+ Profile* profile = BrowserList::GetLastActive()->profile();
+ mediaplayer_browser_ = Browser::CreateForType(Browser::TYPE_APP_PANEL,
+ profile);
+#if defined(OS_CHROMEOS)
+ // Since we are on chromeos, popups should be a PanelBrowserView,
+ // so we can just cast it.
+ if (creator) {
+ chromeos::PanelBrowserView* creatorview =
+ static_cast<chromeos::PanelBrowserView*>(creator->window());
+ chromeos::PanelBrowserView* view =
+ static_cast<chromeos::PanelBrowserView*>(
+ mediaplayer_browser_->window());
+ view->SetCreatorView(creatorview);
+ }
+#endif
+ mediaplayer_browser_->AddSelectedTabWithURL(GURL(kMediaplayerURL),
+ PageTransition::LINK);
+ mediaplayer_browser_->window()->SetBounds(gfx::Rect(kPopupLeft,
+ kPopupTop,
+ kPopupWidth,
+ kPopupHeight));
+ mediaplayer_browser_->window()->Show();
+}
+
+net::URLRequestJob* MediaPlayer::MaybeIntercept(net::URLRequest* request) {
+ // Don't attempt to intercept here as we want to wait until the mime
+ // type is fully determined.
+ return NULL;
+}
+
+// This is the list of mime types currently supported by the Google
+// Document Viewer.
+static const char* const supported_mime_type_list[] = {
+ "audio/mpeg",
+ "video/mp4",
+ "audio/mp3"
+};
+
+net::URLRequestJob* MediaPlayer::MaybeInterceptResponse(
+ net::URLRequest* request) {
+ // Do not intercept this request if it is a download.
+ if (request->load_flags() & net::LOAD_IS_DOWNLOAD) {
+ return NULL;
+ }
+
+ std::string mime_type;
+ request->GetMimeType(&mime_type);
+ // If it is in our list of known URLs, enqueue the url then
+ // Cancel the request so the mediaplayer can handle it when
+ // it hits it in the playlist.
+ if (supported_mime_types_.find(mime_type) != supported_mime_types_.end()) {
+ if (request->referrer() != chrome::kChromeUIMediaplayerURL &&
+ !request->referrer().empty()) {
+ EnqueueMediaURL(request->url(), NULL);
+ request->Cancel();
+ }
+ }
+ return NULL;
+}
+
+MediaPlayer::MediaPlayer()
+ : handler_(NULL),
+ playlist_(NULL),
+ playlist_browser_(NULL),
+ mediaplayer_browser_(NULL),
+ mediaplayer_tab_(NULL),
+ playlist_tab_(NULL) {
+ for (size_t i = 0; i < arraysize(supported_mime_type_list); ++i) {
+ supported_mime_types_.insert(supported_mime_type_list[i]);
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MediaplayerUIContents
+//
+////////////////////////////////////////////////////////////////////////////////
+
+MediaplayerUI::MediaplayerUI(TabContents* contents) : WebUI(contents) {
+ const GURL& url = contents->GetURL();
+ bool is_playlist = (url.ref() == "playlist");
+ MediaplayerHandler* handler = new MediaplayerHandler(is_playlist);
+ AddMessageHandler(handler->Attach(this));
+ if (is_playlist) {
+ handler->Init(true, contents);
+ } else {
+ handler->Init(false, contents);
+ }
+
+ MediaplayerUIHTMLSource* html_source =
+ new MediaplayerUIHTMLSource(is_playlist);
+
+ // Set up the chrome://mediaplayer/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
diff --git a/chrome/browser/ui/webui/mediaplayer_ui.h b/chrome/browser/ui/webui/mediaplayer_ui.h
new file mode 100644
index 0000000..5b5afcf
--- /dev/null
+++ b/chrome/browser/ui/webui/mediaplayer_ui.h
@@ -0,0 +1,161 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_MEDIAPLAYER_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_MEDIAPLAYER_UI_H_
+#pragma once
+
+#include <set>
+#include <vector>
+
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "content/browser/webui/web_ui.h"
+#include "net/base/directory_lister.h"
+#include "net/url_request/url_request.h"
+
+template <typename T> struct DefaultSingletonTraits;
+class GURL;
+class MediaplayerHandler;
+class Browser;
+
+class MediaPlayer : public NotificationObserver,
+ public net::URLRequest::Interceptor {
+ public:
+ ~MediaPlayer();
+
+ // Enqueues this url into the current playlist. If the mediaplayer is
+ // not currently visible, show it, and play the given url.
+ void EnqueueMediaURL(const GURL& url, Browser* creator);
+
+ // Clears out the current playlist, and start playback of the given url.
+ // If there is no mediaplayer currently, show it, and play the given url.
+ void ForcePlayMediaURL(const GURL& url, Browser* creator);
+
+ // Toggle the visibility of the playlist window.
+ void TogglePlaylistWindowVisible();
+
+ // Force the playlist window to be shown.
+ void ShowPlaylistWindow();
+
+ // Toggle the mediaplayer between fullscreen and windowed.
+ void ToggleFullscreen();
+
+ // Force the playlist window to be closed.
+ void ClosePlaylistWindow();
+
+ // Sets the currently playing element to the given offset.
+ void SetPlaylistOffset(int offset);
+
+ // Set a new playback handler to give events to, along with the
+ // tab contents of the page which holds the mediaplayer. it is expected
+ // That only one of these will exist at any given time.
+ void SetNewHandler(MediaplayerHandler* handler,
+ TabContents* contents);
+
+ // Removes the handler.
+ void RemoveHandler(MediaplayerHandler* handler);
+
+ // Registers a new playlist handler which receives events from the
+ // mediaplayer, along with the tab contents which has the playlist in it.
+ void RegisterNewPlaylistHandler(MediaplayerHandler* handler,
+ TabContents* contents);
+
+ // Removes the playlist handler.
+ void RemovePlaylistHandler(MediaplayerHandler* handler);
+
+ // Notfiys the mediaplayer that the playlist changed. This could be
+ // called from the mediaplayer itself for example.
+ void NotifyPlaylistChanged();
+
+ // Always returns NULL because we don't want to attempt a redirect
+ // before seeing the detected mime type of the request.
+ // Implementation of net::URLRequest::Interceptor.
+ virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request);
+
+ // Determines if the requested document can be viewed by the
+ // MediaPlayer. If it can, returns a net::URLRequestJob that
+ // redirects the browser to the view URL.
+ // Implementation of net::URLRequest::Interceptor.
+ virtual net::URLRequestJob* MaybeInterceptResponse(net::URLRequest* request);
+
+ // Used to detect when the mediaplayer is closed.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Getter for the singleton.
+ static MediaPlayer* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<MediaPlayer>;
+
+ MediaPlayer();
+
+ // Popup the mediaplayer, this shows the browser, and sets up its
+ // locations correctly.
+ void PopupMediaPlayer(Browser* creator);
+
+ // Checks to see the the mediaplayer is currently enabled
+ bool Enabled();
+
+ // Popup the playlist. Shows the browser, sets it up to point at
+ // chrome://mediaplayer#playlist
+ void PopupPlaylist(Browser* creator);
+
+ // Registers the listeners for the close events on the browser windows.
+ void RegisterListeners();
+
+ // Set when the register handler is called. When the media player is
+ // closed, this pointer is set back to NULL.
+ MediaplayerHandler* handler_;
+
+ // Set when the register playlist handler is called. When the playlist
+ // is closed, this pointer is set back to NULL.
+ MediaplayerHandler* playlist_;
+
+ // Browser containing the playlist. Used to force closes. This is created
+ // By the PopupPlaylist call, and is NULLed out when the window is closed.
+ Browser* playlist_browser_;
+
+ // Browser containing the Mediaplayer. Used to force closes. This is
+ // created by the PopupMediaplayer call, and is NULLed out when the window
+ // is closed.
+ Browser* mediaplayer_browser_;
+
+ // List of URLs that were enqueued during the time that the mediaplayer
+ // had not poped up yet. This is claered out after the mediaplayer pops up.
+ std::vector<GURL> unhandled_urls_;
+
+ // Used to register for events on the windows, like to listen for closes.
+ NotificationRegistrar registrar_;
+
+ // Tab contents of the mediaplayer. Used to listen for events
+ // which would cause the mediaplayer to be closed. These are cleared out
+ // when the mediaplayer is closed.
+ TabContents* mediaplayer_tab_;
+
+ // Tab contents of the playlist tab. used to listen for events which would
+ // cause the mediaplayer to be closed. These are cleared out when the
+ // playlist is closed.
+ TabContents* playlist_tab_;
+
+ // List of mimetypes that the mediaplayer should listen to. Used for
+ // interceptions of url GETs.
+ std::set<std::string> supported_mime_types_;
+ DISALLOW_COPY_AND_ASSIGN(MediaPlayer);
+};
+
+class MediaplayerUI : public WebUI {
+ public:
+ explicit MediaplayerUI(TabContents* contents);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MediaplayerUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_MEDIAPLAYER_UI_H_
diff --git a/chrome/browser/ui/webui/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals_ui.cc
new file mode 100644
index 0000000..4791c319
--- /dev/null
+++ b/chrome/browser/ui/webui/net_internals_ui.cc
@@ -0,0 +1,1315 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/net_internals_ui.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/singleton.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/io_thread.h"
+#include "chrome/browser/net/chrome_net_log.h"
+#include "chrome/browser/net/connection_tester.h"
+#include "chrome/browser/net/passive_log_collector.h"
+#include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/ui/shell_dialogs.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "chrome/common/url_constants.h"
+#include "grit/generated_resources.h"
+#include "grit/net_internals_resources.h"
+#include "net/base/escape.h"
+#include "net/base/host_resolver_impl.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util.h"
+#include "net/base/sys_addrinfo.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/http/http_alternate_protocols.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_network_layer.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_stream_factory.h"
+#include "net/proxy/proxy_service.h"
+#include "net/url_request/url_request_context.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+#ifdef OS_WIN
+#include "chrome/browser/net/service_providers_win.h"
+#endif
+
+namespace {
+
+// Delay between when an event occurs and when it is passed to the Javascript
+// page. All events that occur during this period are grouped together and
+// sent to the page at once, which reduces context switching and CPU usage.
+const int kNetLogEventDelayMilliseconds = 100;
+
+// Returns the HostCache for |context|'s primary HostResolver, or NULL if
+// there is none.
+net::HostCache* GetHostResolverCache(net::URLRequestContext* context) {
+ net::HostResolverImpl* host_resolver_impl =
+ context->host_resolver()->GetAsHostResolverImpl();
+
+ if (!host_resolver_impl)
+ return NULL;
+
+ return host_resolver_impl->cache();
+}
+
+// Returns the disk cache backend for |context| if there is one, or NULL.
+disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) {
+ if (!context->http_transaction_factory())
+ return NULL;
+
+ net::HttpCache* http_cache = context->http_transaction_factory()->GetCache();
+ if (!http_cache)
+ return NULL;
+
+ return http_cache->GetCurrentBackend();
+}
+
+// Returns the http network session for |context| if there is one.
+// Otherwise, returns NULL.
+net::HttpNetworkSession* GetHttpNetworkSession(
+ net::URLRequestContext* context) {
+ if (!context->http_transaction_factory())
+ return NULL;
+
+ return context->http_transaction_factory()->GetSession();
+}
+
+Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) {
+ DictionaryValue* dict = new DictionaryValue();
+
+ if (experiment.url.is_valid())
+ dict->SetString("url", experiment.url.spec());
+
+ dict->SetString("proxy_settings_experiment",
+ ConnectionTester::ProxySettingsExperimentDescription(
+ experiment.proxy_settings_experiment));
+ dict->SetString("host_resolver_experiment",
+ ConnectionTester::HostResolverExperimentDescription(
+ experiment.host_resolver_experiment));
+ return dict;
+}
+
+class NetInternalsHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ NetInternalsHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const;
+
+ private:
+ ~NetInternalsHTMLSource() {}
+ DISALLOW_COPY_AND_ASSIGN(NetInternalsHTMLSource);
+};
+
+// This class receives javascript messages from the renderer.
+// Note that the WebUI infrastructure runs on the UI thread, therefore all of
+// this class's methods are expected to run on the UI thread.
+//
+// Since the network code we want to run lives on the IO thread, we proxy
+// everything over to NetInternalsMessageHandler::IOThreadImpl, which runs
+// on the IO thread.
+//
+// TODO(eroman): Can we start on the IO thread to begin with?
+class NetInternalsMessageHandler
+ : public WebUIMessageHandler,
+ public SelectFileDialog::Listener,
+ public base::SupportsWeakPtr<NetInternalsMessageHandler> {
+ public:
+ NetInternalsMessageHandler();
+ virtual ~NetInternalsMessageHandler();
+
+ // WebUIMessageHandler implementation.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+ virtual void RegisterMessages();
+
+ // Executes the javascript function |function_name| in the renderer, passing
+ // it the argument |value|.
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value* value);
+
+ // SelectFileDialog::Listener implementation
+ virtual void FileSelected(const FilePath& path, int index, void* params);
+ virtual void FileSelectionCanceled(void* params);
+
+ // The only callback handled on the UI thread. As it needs to access fields
+ // from |web_ui_|, it can't be called on the IO thread.
+ void OnLoadLogFile(const ListValue* list);
+
+ private:
+ class IOThreadImpl;
+
+ // Task run on the FILE thread to read the contents of a log file. The result
+ // is then passed to IOThreadImpl's CallJavascriptFunction, which sends it
+ // back to the web page. IOThreadImpl is used instead of the
+ // NetInternalsMessageHandler directly because it checks if the message
+ // handler has been destroyed in the meantime.
+ class ReadLogFileTask : public Task {
+ public:
+ ReadLogFileTask(IOThreadImpl* proxy, const FilePath& path);
+
+ virtual void Run();
+
+ private:
+ // IOThreadImpl implements existence checks already. Simpler to reused them
+ // then to reimplement them.
+ scoped_refptr<IOThreadImpl> proxy_;
+
+ // Path of the file to open.
+ const FilePath path_;
+ };
+
+ // This is the "real" message handler, which lives on the IO thread.
+ scoped_refptr<IOThreadImpl> proxy_;
+
+ // Used for loading log files.
+ scoped_refptr<SelectFileDialog> select_log_file_dialog_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler);
+};
+
+// This class is the "real" message handler. It is allocated and destroyed on
+// the UI thread. With the exception of OnAddEntry, OnWebUIDeleted, and
+// CallJavascriptFunction, its methods are all expected to be called from the IO
+// thread. OnAddEntry and CallJavascriptFunction can be called from any thread,
+// and OnWebUIDeleted can only be called from the UI thread.
+class NetInternalsMessageHandler::IOThreadImpl
+ : public base::RefCountedThreadSafe<
+ NetInternalsMessageHandler::IOThreadImpl,
+ BrowserThread::DeleteOnUIThread>,
+ public ChromeNetLog::ThreadSafeObserver,
+ public ConnectionTester::Delegate {
+ public:
+ // Type for methods that can be used as MessageHandler callbacks.
+ typedef void (IOThreadImpl::*MessageHandler)(const ListValue*);
+
+ // Creates a proxy for |handler| that will live on the IO thread.
+ // |handler| is a weak pointer, since it is possible for the
+ // WebUIMessageHandler to be deleted on the UI thread while we were executing
+ // on the IO thread. |io_thread| is the global IOThread (it is passed in as
+ // an argument since we need to grab it from the UI thread).
+ IOThreadImpl(
+ const base::WeakPtr<NetInternalsMessageHandler>& handler,
+ IOThread* io_thread,
+ URLRequestContextGetter* context_getter);
+
+ ~IOThreadImpl();
+
+ // Creates a callback that will run |method| on the IO thread.
+ //
+ // This can be used with WebUI::RegisterMessageCallback() to bind to a method
+ // on the IO thread.
+ WebUI::MessageCallback* CreateCallback(MessageHandler method);
+
+ // Called once the WebUI has been deleted (i.e. renderer went away), on the
+ // IO thread.
+ void Detach();
+
+ // Sends all passive log entries in |passive_entries| to the Javascript
+ // handler, called on the IO thread.
+ void SendPassiveLogEntries(const ChromeNetLog::EntryList& passive_entries);
+
+ // Called when the WebUI is deleted. Prevents calling Javascript functions
+ // afterwards. Called on UI thread.
+ void OnWebUIDeleted();
+
+ //--------------------------------
+ // Javascript message handlers:
+ //--------------------------------
+
+ void OnRendererReady(const ListValue* list);
+
+ void OnGetProxySettings(const ListValue* list);
+ void OnReloadProxySettings(const ListValue* list);
+ void OnGetBadProxies(const ListValue* list);
+ void OnClearBadProxies(const ListValue* list);
+ void OnGetHostResolverInfo(const ListValue* list);
+ void OnClearHostResolverCache(const ListValue* list);
+ void OnEnableIPv6(const ListValue* list);
+ void OnStartConnectionTests(const ListValue* list);
+ void OnHSTSQuery(const ListValue* list);
+ void OnHSTSAdd(const ListValue* list);
+ void OnHSTSDelete(const ListValue* list);
+ void OnGetHttpCacheInfo(const ListValue* list);
+ void OnGetSocketPoolInfo(const ListValue* list);
+ void OnGetSpdySessionInfo(const ListValue* list);
+ void OnGetSpdyStatus(const ListValue* list);
+ void OnGetSpdyAlternateProtocolMappings(const ListValue* list);
+#ifdef OS_WIN
+ void OnGetServiceProviders(const ListValue* list);
+#endif
+
+ void OnSetLogLevel(const ListValue* list);
+
+ // ChromeNetLog::ThreadSafeObserver implementation:
+ virtual void OnAddEntry(net::NetLog::EventType type,
+ const base::TimeTicks& time,
+ const net::NetLog::Source& source,
+ net::NetLog::EventPhase phase,
+ net::NetLog::EventParameters* params);
+
+ // ConnectionTester::Delegate implementation:
+ virtual void OnStartConnectionTestSuite();
+ virtual void OnStartConnectionTestExperiment(
+ const ConnectionTester::Experiment& experiment);
+ virtual void OnCompletedConnectionTestExperiment(
+ const ConnectionTester::Experiment& experiment,
+ int result);
+ virtual void OnCompletedConnectionTestSuite();
+
+ // Helper that executes |function_name| in the attached renderer.
+ // The function takes ownership of |arg|. Note that this can be called from
+ // any thread.
+ void CallJavascriptFunction(const std::wstring& function_name, Value* arg);
+
+ private:
+ class CallbackHelper;
+
+ // Helper that runs |method| with |arg|, and deletes |arg| on completion.
+ void DispatchToMessageHandler(ListValue* arg, MessageHandler method);
+
+ // Adds |entry| to the queue of pending log entries to be sent to the page via
+ // Javascript. Must be called on the IO Thread. Also creates a delayed task
+ // that will call PostPendingEntries, if there isn't one already.
+ void AddEntryToQueue(Value* entry);
+
+ // Sends all pending entries to the page via Javascript, and clears the list
+ // of pending entries. Sending multiple entries at once results in a
+ // significant reduction of CPU usage when a lot of events are happening.
+ // Must be called on the IO Thread.
+ void PostPendingEntries();
+
+ // Pointer to the UI-thread message handler. Only access this from
+ // the UI thread.
+ base::WeakPtr<NetInternalsMessageHandler> handler_;
+
+ // The global IOThread, which contains the global NetLog to observer.
+ IOThread* io_thread_;
+
+ scoped_refptr<URLRequestContextGetter> context_getter_;
+
+ // Helper that runs the suite of connection tests.
+ scoped_ptr<ConnectionTester> connection_tester_;
+
+ // True if the Web UI has been deleted. This is used to prevent calling
+ // Javascript functions after the Web UI is destroyed. On refresh, the
+ // messages can end up being sent to the refreshed page, causing duplicate
+ // or partial entries.
+ //
+ // This is only read and written to on the UI thread.
+ bool was_webui_deleted_;
+
+ // True if we have attached an observer to the NetLog already.
+ bool is_observing_log_;
+ friend class base::RefCountedThreadSafe<IOThreadImpl>;
+
+ // Log entries that have yet to be passed along to Javascript page. Non-NULL
+ // when and only when there is a pending delayed task to call
+ // PostPendingEntries. Read and written to exclusively on the IO Thread.
+ scoped_ptr<ListValue> pending_entries_;
+};
+
+// Helper class for a WebUI::MessageCallback which when excuted calls
+// instance->*method(value) on the IO thread.
+class NetInternalsMessageHandler::IOThreadImpl::CallbackHelper
+ : public WebUI::MessageCallback {
+ public:
+ CallbackHelper(IOThreadImpl* instance, IOThreadImpl::MessageHandler method)
+ : instance_(instance),
+ method_(method) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ }
+
+ virtual void RunWithParams(const Tuple1<const ListValue*>& params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // We need to make a copy of the value in order to pass it over to the IO
+ // thread. We will delete this in IOThreadImpl::DispatchMessageHandler().
+ ListValue* list_copy = static_cast<ListValue*>(
+ params.a ? params.a->DeepCopy() : NULL);
+
+ if (!BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(instance_.get(),
+ &IOThreadImpl::DispatchToMessageHandler,
+ list_copy, method_))) {
+ // Failed posting the task, avoid leaking |list_copy|.
+ delete list_copy;
+ }
+ }
+
+ private:
+ scoped_refptr<IOThreadImpl> instance_;
+ IOThreadImpl::MessageHandler method_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NetInternalsHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+NetInternalsHTMLSource::NetInternalsHTMLSource()
+ : DataSource(chrome::kChromeUINetInternalsHost, MessageLoop::current()) {
+}
+
+void NetInternalsHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ SetFontAndTextDirection(&localized_strings);
+
+ // The provided "path" may contain a fragment, or query section. We only
+ // care about the path itself, and will disregard anything else.
+ std::string filename =
+ GURL(std::string("chrome://net/") + path).path().substr(1);
+
+ // The source for the net internals page is flattened during compilation, so
+ // the only resource that should legitimately be requested is the main file.
+ // Note that users can type anything into the address bar, though, so we must
+ // handle arbitrary input.
+ if (filename.empty() || filename == "index.html") {
+ base::StringPiece html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_NET_INTERNALS_INDEX_HTML));
+ std::string full_html(html.data(), html.size());
+ jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
+ jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
+ jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
+ jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+ SendResponse(request_id, html_bytes);
+ return;
+ }
+
+ const std::string data_string("<p style='color:red'>Failed to read resource" +
+ EscapeForHTML(filename) + "</p>");
+ scoped_refptr<RefCountedBytes> bytes(new RefCountedBytes);
+ bytes->data.resize(data_string.size());
+ std::copy(data_string.begin(), data_string.end(), bytes->data.begin());
+ SendResponse(request_id, bytes);
+}
+
+std::string NetInternalsHTMLSource::GetMimeType(const std::string&) const {
+ return "text/html";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NetInternalsMessageHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+NetInternalsMessageHandler::NetInternalsMessageHandler() {}
+
+NetInternalsMessageHandler::~NetInternalsMessageHandler() {
+ if (proxy_) {
+ proxy_.get()->OnWebUIDeleted();
+ // Notify the handler on the IO thread that the renderer is gone.
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(proxy_.get(), &IOThreadImpl::Detach));
+ }
+ if (select_log_file_dialog_)
+ select_log_file_dialog_->ListenerDestroyed();
+}
+
+WebUIMessageHandler* NetInternalsMessageHandler::Attach(WebUI* web_ui) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(),
+ web_ui->GetProfile()->GetRequestContext());
+ WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui);
+ return result;
+}
+
+void NetInternalsMessageHandler::FileSelected(
+ const FilePath& path, int index, void* params) {
+ select_log_file_dialog_.release();
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ new ReadLogFileTask(proxy_.get(), path));
+}
+
+void NetInternalsMessageHandler::FileSelectionCanceled(void* params) {
+ select_log_file_dialog_.release();
+}
+
+void NetInternalsMessageHandler::OnLoadLogFile(const ListValue* list) {
+ // Only allow a single dialog at a time.
+ if (select_log_file_dialog_.get())
+ return;
+ select_log_file_dialog_ = SelectFileDialog::Create(this);
+ select_log_file_dialog_->SelectFile(
+ SelectFileDialog::SELECT_OPEN_FILE, string16(), FilePath(), NULL, 0,
+ FILE_PATH_LITERAL(""),
+ web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL);
+}
+
+void NetInternalsMessageHandler::RegisterMessages() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // Only callback handled on UI thread.
+ web_ui_->RegisterMessageCallback(
+ "loadLogFile",
+ NewCallback(this, &NetInternalsMessageHandler::OnLoadLogFile));
+
+ web_ui_->RegisterMessageCallback(
+ "notifyReady",
+ proxy_->CreateCallback(&IOThreadImpl::OnRendererReady));
+ web_ui_->RegisterMessageCallback(
+ "getProxySettings",
+ proxy_->CreateCallback(&IOThreadImpl::OnGetProxySettings));
+ web_ui_->RegisterMessageCallback(
+ "reloadProxySettings",
+ proxy_->CreateCallback(&IOThreadImpl::OnReloadProxySettings));
+ web_ui_->RegisterMessageCallback(
+ "getBadProxies",
+ proxy_->CreateCallback(&IOThreadImpl::OnGetBadProxies));
+ web_ui_->RegisterMessageCallback(
+ "clearBadProxies",
+ proxy_->CreateCallback(&IOThreadImpl::OnClearBadProxies));
+ web_ui_->RegisterMessageCallback(
+ "getHostResolverInfo",
+ proxy_->CreateCallback(&IOThreadImpl::OnGetHostResolverInfo));
+ web_ui_->RegisterMessageCallback(
+ "clearHostResolverCache",
+ proxy_->CreateCallback(&IOThreadImpl::OnClearHostResolverCache));
+ web_ui_->RegisterMessageCallback(
+ "enableIPv6",
+ proxy_->CreateCallback(&IOThreadImpl::OnEnableIPv6));
+ web_ui_->RegisterMessageCallback(
+ "startConnectionTests",
+ proxy_->CreateCallback(&IOThreadImpl::OnStartConnectionTests));
+ web_ui_->RegisterMessageCallback(
+ "hstsQuery",
+ proxy_->CreateCallback(&IOThreadImpl::OnHSTSQuery));
+ web_ui_->RegisterMessageCallback(
+ "hstsAdd",
+ proxy_->CreateCallback(&IOThreadImpl::OnHSTSAdd));
+ web_ui_->RegisterMessageCallback(
+ "hstsDelete",
+ proxy_->CreateCallback(&IOThreadImpl::OnHSTSDelete));
+ web_ui_->RegisterMessageCallback(
+ "getHttpCacheInfo",
+ proxy_->CreateCallback(&IOThreadImpl::OnGetHttpCacheInfo));
+ web_ui_->RegisterMessageCallback(
+ "getSocketPoolInfo",
+ proxy_->CreateCallback(&IOThreadImpl::OnGetSocketPoolInfo));
+ web_ui_->RegisterMessageCallback(
+ "getSpdySessionInfo",
+ proxy_->CreateCallback(&IOThreadImpl::OnGetSpdySessionInfo));
+ web_ui_->RegisterMessageCallback(
+ "getSpdyStatus",
+ proxy_->CreateCallback(&IOThreadImpl::OnGetSpdyStatus));
+ web_ui_->RegisterMessageCallback(
+ "getSpdyAlternateProtocolMappings",
+ proxy_->CreateCallback(
+ &IOThreadImpl::OnGetSpdyAlternateProtocolMappings));
+#ifdef OS_WIN
+ web_ui_->RegisterMessageCallback(
+ "getServiceProviders",
+ proxy_->CreateCallback(&IOThreadImpl::OnGetServiceProviders));
+#endif
+
+ web_ui_->RegisterMessageCallback(
+ "setLogLevel",
+ proxy_->CreateCallback(&IOThreadImpl::OnSetLogLevel));
+}
+
+void NetInternalsMessageHandler::CallJavascriptFunction(
+ const std::wstring& function_name,
+ const Value* value) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (value) {
+ web_ui_->CallJavascriptFunction(function_name, *value);
+ } else {
+ web_ui_->CallJavascriptFunction(function_name);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NetInternalsMessageHandler::ReadLogFileTask
+//
+////////////////////////////////////////////////////////////////////////////////
+
+NetInternalsMessageHandler::ReadLogFileTask::ReadLogFileTask(
+ IOThreadImpl* proxy, const FilePath& path)
+ : proxy_(proxy), path_(path) {
+}
+
+void NetInternalsMessageHandler::ReadLogFileTask::Run() {
+ std::string file_contents;
+ if (!file_util::ReadFileToString(path_, &file_contents))
+ return;
+ proxy_->CallJavascriptFunction(L"g_browser.loadedLogFile",
+ new StringValue(file_contents));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NetInternalsMessageHandler::IOThreadImpl
+//
+////////////////////////////////////////////////////////////////////////////////
+
+NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
+ const base::WeakPtr<NetInternalsMessageHandler>& handler,
+ IOThread* io_thread,
+ URLRequestContextGetter* context_getter)
+ : ThreadSafeObserver(net::NetLog::LOG_ALL_BUT_BYTES),
+ handler_(handler),
+ io_thread_(io_thread),
+ context_getter_(context_getter),
+ was_webui_deleted_(false),
+ is_observing_log_(false) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+WebUI::MessageCallback*
+NetInternalsMessageHandler::IOThreadImpl::CreateCallback(
+ MessageHandler method) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return new CallbackHelper(this, method);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::Detach() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Unregister with network stack to observe events.
+ if (is_observing_log_)
+ io_thread_->net_log()->RemoveObserver(this);
+
+ // Cancel any in-progress connection tests.
+ connection_tester_.reset();
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::SendPassiveLogEntries(
+ const ChromeNetLog::EntryList& passive_entries) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ListValue* dict_list = new ListValue();
+ for (size_t i = 0; i < passive_entries.size(); ++i) {
+ const ChromeNetLog::Entry& e = passive_entries[i];
+ dict_list->Append(net::NetLog::EntryToDictionaryValue(e.type,
+ e.time,
+ e.source,
+ e.phase,
+ e.params,
+ false));
+ }
+
+ CallJavascriptFunction(L"g_browser.receivedPassiveLogEntries", dict_list);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ was_webui_deleted_ = true;
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
+ const ListValue* list) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(!is_observing_log_) << "notifyReady called twice";
+
+ // Tell the javascript about the relationship between event type enums and
+ // their symbolic name.
+ {
+ std::vector<net::NetLog::EventType> event_types =
+ net::NetLog::GetAllEventTypes();
+
+ DictionaryValue* dict = new DictionaryValue();
+
+ for (size_t i = 0; i < event_types.size(); ++i) {
+ const char* name = net::NetLog::EventTypeToString(event_types[i]);
+ dict->SetInteger(name, static_cast<int>(event_types[i]));
+ }
+
+ CallJavascriptFunction(L"g_browser.receivedLogEventTypeConstants", dict);
+ }
+
+ // Tell the javascript about the version of the client and its
+ // command line arguments.
+ {
+ DictionaryValue* dict = new DictionaryValue();
+
+ chrome::VersionInfo version_info;
+
+ if (!version_info.is_valid()) {
+ DLOG(ERROR) << "Unable to create chrome::VersionInfo";
+ } else {
+ // We have everything we need to send the right values.
+ dict->SetString("version", version_info.Version());
+ dict->SetString("cl", version_info.LastChange());
+ dict->SetString("version_mod",
+ platform_util::GetVersionStringModifier());
+ dict->SetString("official",
+ l10n_util::GetStringUTF16(
+ version_info.IsOfficialBuild() ?
+ IDS_ABOUT_VERSION_OFFICIAL
+ : IDS_ABOUT_VERSION_UNOFFICIAL));
+
+ dict->SetString("command_line",
+ CommandLine::ForCurrentProcess()->command_line_string());
+ }
+
+ CallJavascriptFunction(L"g_browser.receivedClientInfo",
+ dict);
+ }
+
+ // Tell the javascript about the relationship between load flag enums and
+ // their symbolic name.
+ {
+ DictionaryValue* dict = new DictionaryValue();
+
+#define LOAD_FLAG(label, value) \
+ dict->SetInteger(# label, static_cast<int>(value));
+#include "net/base/load_flags_list.h"
+#undef LOAD_FLAG
+
+ CallJavascriptFunction(L"g_browser.receivedLoadFlagConstants", dict);
+ }
+
+ // Tell the javascript about the relationship between net error codes and
+ // their symbolic name.
+ {
+ DictionaryValue* dict = new DictionaryValue();
+
+#define NET_ERROR(label, value) \
+ dict->SetInteger(# label, static_cast<int>(value));
+#include "net/base/net_error_list.h"
+#undef NET_ERROR
+
+ CallJavascriptFunction(L"g_browser.receivedNetErrorConstants", dict);
+ }
+
+ // Tell the javascript about the relationship between event phase enums and
+ // their symbolic name.
+ {
+ DictionaryValue* dict = new DictionaryValue();
+
+ dict->SetInteger("PHASE_BEGIN", net::NetLog::PHASE_BEGIN);
+ dict->SetInteger("PHASE_END", net::NetLog::PHASE_END);
+ dict->SetInteger("PHASE_NONE", net::NetLog::PHASE_NONE);
+
+ CallJavascriptFunction(L"g_browser.receivedLogEventPhaseConstants", dict);
+ }
+
+ // Tell the javascript about the relationship between source type enums and
+ // their symbolic names.
+ {
+ DictionaryValue* dict = new DictionaryValue();
+
+#define SOURCE_TYPE(label, value) dict->SetInteger(# label, value);
+#include "net/base/net_log_source_type_list.h"
+#undef SOURCE_TYPE
+
+ CallJavascriptFunction(L"g_browser.receivedLogSourceTypeConstants", dict);
+ }
+
+ // Tell the javascript about the relationship between LogLevel enums and their
+ // symbolic names.
+ {
+ DictionaryValue* dict = new DictionaryValue();
+
+ dict->SetInteger("LOG_ALL", net::NetLog::LOG_ALL);
+ dict->SetInteger("LOG_ALL_BUT_BYTES", net::NetLog::LOG_ALL_BUT_BYTES);
+ dict->SetInteger("LOG_BASIC", net::NetLog::LOG_BASIC);
+
+ CallJavascriptFunction(L"g_browser.receivedLogLevelConstants", dict);
+ }
+
+ // Tell the javascript about the relationship between address family enums and
+ // their symbolic names.
+ {
+ DictionaryValue* dict = new DictionaryValue();
+
+ dict->SetInteger("ADDRESS_FAMILY_UNSPECIFIED",
+ net::ADDRESS_FAMILY_UNSPECIFIED);
+ dict->SetInteger("ADDRESS_FAMILY_IPV4",
+ net::ADDRESS_FAMILY_IPV4);
+ dict->SetInteger("ADDRESS_FAMILY_IPV6",
+ net::ADDRESS_FAMILY_IPV6);
+
+ CallJavascriptFunction(L"g_browser.receivedAddressFamilyConstants", dict);
+ }
+
+ // Tell the javascript how the "time ticks" values we have given it relate to
+ // actual system times. (We used time ticks throughout since they are stable
+ // across system clock changes).
+ {
+ int64 cur_time_ms = (base::Time::Now() - base::Time()).InMilliseconds();
+
+ int64 cur_time_ticks_ms =
+ (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
+
+ // If we add this number to a time tick value, it gives the timestamp.
+ int64 tick_to_time_ms = cur_time_ms - cur_time_ticks_ms;
+
+ // Chrome on all platforms stores times using the Windows epoch
+ // (Jan 1 1601), but the javascript wants a unix epoch.
+ // TODO(eroman): Getting the timestamp relative the to unix epoch should
+ // be part of the time library.
+ const int64 kUnixEpochMs = 11644473600000LL;
+ int64 tick_to_unix_time_ms = tick_to_time_ms - kUnixEpochMs;
+
+ // Pass it as a string, since it may be too large to fit in an integer.
+ CallJavascriptFunction(L"g_browser.receivedTimeTickOffset",
+ Value::CreateStringValue(
+ base::Int64ToString(tick_to_unix_time_ms)));
+ }
+
+ // Register with network stack to observe events.
+ is_observing_log_ = true;
+ ChromeNetLog::EntryList entries;
+ io_thread_->net_log()->AddObserverAndGetAllPassivelyCapturedEvents(this,
+ &entries);
+ SendPassiveLogEntries(entries);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings(
+ const ListValue* list) {
+ net::URLRequestContext* context = context_getter_->GetURLRequestContext();
+ net::ProxyService* proxy_service = context->proxy_service();
+
+ DictionaryValue* dict = new DictionaryValue();
+ if (proxy_service->fetched_config().is_valid())
+ dict->Set("original", proxy_service->fetched_config().ToValue());
+ if (proxy_service->config().is_valid())
+ dict->Set("effective", proxy_service->config().ToValue());
+
+ CallJavascriptFunction(L"g_browser.receivedProxySettings", dict);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
+ const ListValue* list) {
+ net::URLRequestContext* context = context_getter_->GetURLRequestContext();
+ context->proxy_service()->ForceReloadProxyConfig();
+
+ // Cause the renderer to be notified of the new values.
+ OnGetProxySettings(NULL);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies(
+ const ListValue* list) {
+ net::URLRequestContext* context = context_getter_->GetURLRequestContext();
+
+ const net::ProxyRetryInfoMap& bad_proxies_map =
+ context->proxy_service()->proxy_retry_info();
+
+ ListValue* dict_list = new ListValue();
+
+ for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin();
+ it != bad_proxies_map.end(); ++it) {
+ const std::string& proxy_uri = it->first;
+ const net::ProxyRetryInfo& retry_info = it->second;
+
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("proxy_uri", proxy_uri);
+ dict->SetString("bad_until",
+ net::NetLog::TickCountToString(retry_info.bad_until));
+
+ dict_list->Append(dict);
+ }
+
+ CallJavascriptFunction(L"g_browser.receivedBadProxies", dict_list);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
+ const ListValue* list) {
+ net::URLRequestContext* context = context_getter_->GetURLRequestContext();
+ context->proxy_service()->ClearBadProxiesCache();
+
+ // Cause the renderer to be notified of the new values.
+ OnGetBadProxies(NULL);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverInfo(
+ const ListValue* list) {
+ net::URLRequestContext* context = context_getter_->GetURLRequestContext();
+ net::HostResolverImpl* host_resolver_impl =
+ context->host_resolver()->GetAsHostResolverImpl();
+ net::HostCache* cache = GetHostResolverCache(context);
+
+ if (!host_resolver_impl || !cache) {
+ CallJavascriptFunction(L"g_browser.receivedHostResolverInfo", NULL);
+ return;
+ }
+
+ DictionaryValue* dict = new DictionaryValue();
+
+ dict->SetInteger(
+ "default_address_family",
+ static_cast<int>(host_resolver_impl->GetDefaultAddressFamily()));
+
+ DictionaryValue* cache_info_dict = new DictionaryValue();
+
+ cache_info_dict->SetInteger(
+ "capacity",
+ static_cast<int>(cache->max_entries()));
+ cache_info_dict->SetInteger(
+ "ttl_success_ms",
+ static_cast<int>(cache->success_entry_ttl().InMilliseconds()));
+ cache_info_dict->SetInteger(
+ "ttl_failure_ms",
+ static_cast<int>(cache->failure_entry_ttl().InMilliseconds()));
+
+ ListValue* entry_list = new ListValue();
+
+ for (net::HostCache::EntryMap::const_iterator it =
+ cache->entries().begin();
+ it != cache->entries().end();
+ ++it) {
+ const net::HostCache::Key& key = it->first;
+ const net::HostCache::Entry* entry = it->second.get();
+
+ DictionaryValue* entry_dict = new DictionaryValue();
+
+ entry_dict->SetString("hostname", key.hostname);
+ entry_dict->SetInteger("address_family",
+ static_cast<int>(key.address_family));
+ entry_dict->SetString("expiration",
+ net::NetLog::TickCountToString(entry->expiration));
+
+ if (entry->error != net::OK) {
+ entry_dict->SetInteger("error", entry->error);
+ } else {
+ // Append all of the resolved addresses.
+ ListValue* address_list = new ListValue();
+ const struct addrinfo* current_address = entry->addrlist.head();
+ while (current_address) {
+ address_list->Append(Value::CreateStringValue(
+ net::NetAddressToStringWithPort(current_address)));
+ current_address = current_address->ai_next;
+ }
+ entry_dict->Set("addresses", address_list);
+ }
+
+ entry_list->Append(entry_dict);
+ }
+
+ cache_info_dict->Set("entries", entry_list);
+ dict->Set("cache", cache_info_dict);
+
+ CallJavascriptFunction(L"g_browser.receivedHostResolverInfo", dict);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
+ const ListValue* list) {
+ net::HostCache* cache =
+ GetHostResolverCache(context_getter_->GetURLRequestContext());
+
+ if (cache)
+ cache->clear();
+
+ // Cause the renderer to be notified of the new values.
+ OnGetHostResolverInfo(NULL);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6(
+ const ListValue* list) {
+ net::URLRequestContext* context = context_getter_->GetURLRequestContext();
+ net::HostResolverImpl* host_resolver_impl =
+ context->host_resolver()->GetAsHostResolverImpl();
+
+ if (host_resolver_impl) {
+ host_resolver_impl->SetDefaultAddressFamily(
+ net::ADDRESS_FAMILY_UNSPECIFIED);
+ }
+
+ // Cause the renderer to be notified of the new value.
+ OnGetHostResolverInfo(NULL);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
+ const ListValue* list) {
+ // |value| should be: [<URL to test>].
+ string16 url_str;
+ CHECK(list->GetString(0, &url_str));
+
+ // Try to fix-up the user provided URL into something valid.
+ // For example, turn "www.google.com" into "http://www.google.com".
+ GURL url(URLFixerUpper::FixupURL(UTF16ToUTF8(url_str), std::string()));
+
+ connection_tester_.reset(new ConnectionTester(
+ this, io_thread_->globals()->proxy_script_fetcher_context.get()));
+ connection_tester_->RunAllTests(url);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery(
+ const ListValue* list) {
+ // |list| should be: [<domain to query>].
+ std::string domain;
+ CHECK(list->GetString(0, &domain));
+ DictionaryValue* result = new(DictionaryValue);
+
+ if (!IsStringASCII(domain)) {
+ result->SetString("error", "non-ASCII domain name");
+ } else {
+ net::TransportSecurityState* transport_security_state =
+ context_getter_->GetURLRequestContext()->transport_security_state();
+ if (!transport_security_state) {
+ result->SetString("error", "no TransportSecurityState active");
+ } else {
+ net::TransportSecurityState::DomainState state;
+ const bool found = transport_security_state->IsEnabledForHost(
+ &state, domain);
+
+ result->SetBoolean("result", found);
+ if (found) {
+ result->SetInteger("mode", static_cast<int>(state.mode));
+ result->SetBoolean("subdomains", state.include_subdomains);
+ result->SetBoolean("preloaded", state.preloaded);
+ result->SetString("domain", state.domain);
+ }
+ }
+ }
+
+ CallJavascriptFunction(L"g_browser.receivedHSTSResult", result);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd(
+ const ListValue* list) {
+ // |list| should be: [<domain to query>, <include subdomains>].
+ std::string domain;
+ CHECK(list->GetString(0, &domain));
+ if (!IsStringASCII(domain)) {
+ // Silently fail. The user will get a helpful error if they query for the
+ // name.
+ return;
+ }
+ bool include_subdomains;
+ CHECK(list->GetBoolean(1, &include_subdomains));
+
+ net::TransportSecurityState* transport_security_state =
+ context_getter_->GetURLRequestContext()->transport_security_state();
+ if (!transport_security_state)
+ return;
+
+ net::TransportSecurityState::DomainState state;
+ state.expiry = state.created + base::TimeDelta::FromDays(1000);
+ state.include_subdomains = include_subdomains;
+
+ transport_security_state->EnableHost(domain, state);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete(
+ const ListValue* list) {
+ // |list| should be: [<domain to query>].
+ std::string domain;
+ CHECK(list->GetString(0, &domain));
+ if (!IsStringASCII(domain)) {
+ // There cannot be a unicode entry in the HSTS set.
+ return;
+ }
+ net::TransportSecurityState* transport_security_state =
+ context_getter_->GetURLRequestContext()->transport_security_state();
+ if (!transport_security_state)
+ return;
+
+ transport_security_state->DeleteHost(domain);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo(
+ const ListValue* list) {
+ DictionaryValue* info_dict = new DictionaryValue();
+ DictionaryValue* stats_dict = new DictionaryValue();
+
+ disk_cache::Backend* disk_cache = GetDiskCacheBackend(
+ context_getter_->GetURLRequestContext());
+
+ if (disk_cache) {
+ // Extract the statistics key/value pairs from the backend.
+ std::vector<std::pair<std::string, std::string> > stats;
+ disk_cache->GetStats(&stats);
+ for (size_t i = 0; i < stats.size(); ++i) {
+ stats_dict->Set(stats[i].first,
+ Value::CreateStringValue(stats[i].second));
+ }
+ }
+
+ info_dict->Set("stats", stats_dict);
+
+ CallJavascriptFunction(L"g_browser.receivedHttpCacheInfo", info_dict);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo(
+ const ListValue* list) {
+ net::HttpNetworkSession* http_network_session =
+ GetHttpNetworkSession(context_getter_->GetURLRequestContext());
+
+ Value* socket_pool_info = NULL;
+ if (http_network_session)
+ socket_pool_info = http_network_session->SocketPoolInfoToValue();
+
+ CallJavascriptFunction(L"g_browser.receivedSocketPoolInfo", socket_pool_info);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdySessionInfo(
+ const ListValue* list) {
+ net::HttpNetworkSession* http_network_session =
+ GetHttpNetworkSession(context_getter_->GetURLRequestContext());
+
+ Value* spdy_info = NULL;
+ if (http_network_session) {
+ spdy_info = http_network_session->SpdySessionPoolInfoToValue();
+ }
+
+ CallJavascriptFunction(L"g_browser.receivedSpdySessionInfo", spdy_info);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyStatus(
+ const ListValue* list) {
+ DictionaryValue* status_dict = new DictionaryValue();
+
+ status_dict->Set("spdy_enabled",
+ Value::CreateBooleanValue(
+ net::HttpStreamFactory::spdy_enabled()));
+ status_dict->Set("use_alternate_protocols",
+ Value::CreateBooleanValue(
+ net::HttpStreamFactory::use_alternate_protocols()));
+ status_dict->Set("force_spdy_over_ssl",
+ Value::CreateBooleanValue(
+ net::HttpStreamFactory::force_spdy_over_ssl()));
+ status_dict->Set("force_spdy_always",
+ Value::CreateBooleanValue(
+ net::HttpStreamFactory::force_spdy_always()));
+ status_dict->Set("next_protos",
+ Value::CreateStringValue(
+ *net::HttpStreamFactory::next_protos()));
+
+ CallJavascriptFunction(L"g_browser.receivedSpdyStatus", status_dict);
+}
+
+void
+NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyAlternateProtocolMappings(
+ const ListValue* list) {
+ net::HttpNetworkSession* http_network_session =
+ GetHttpNetworkSession(context_getter_->GetURLRequestContext());
+
+ ListValue* dict_list = new ListValue();
+
+ if (http_network_session) {
+ const net::HttpAlternateProtocols& http_alternate_protocols =
+ http_network_session->alternate_protocols();
+ const net::HttpAlternateProtocols::ProtocolMap& map =
+ http_alternate_protocols.protocol_map();
+
+ for (net::HttpAlternateProtocols::ProtocolMap::const_iterator it =
+ map.begin();
+ it != map.end(); ++it) {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("host_port_pair", it->first.ToString());
+ dict->SetString("alternate_protocol", it->second.ToString());
+ dict_list->Append(dict);
+ }
+ }
+
+ CallJavascriptFunction(L"g_browser.receivedSpdyAlternateProtocolMappings",
+ dict_list);
+}
+
+#ifdef OS_WIN
+void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders(
+ const ListValue* list) {
+
+ DictionaryValue* service_providers = new DictionaryValue();
+
+ WinsockLayeredServiceProviderList layered_providers;
+ GetWinsockLayeredServiceProviders(&layered_providers);
+ ListValue* layered_provider_list = new ListValue();
+ for (size_t i = 0; i < layered_providers.size(); ++i) {
+ DictionaryValue* service_dict = new DictionaryValue();
+ service_dict->SetString("name", layered_providers[i].name);
+ service_dict->SetInteger("version", layered_providers[i].version);
+ service_dict->SetInteger("chain_length", layered_providers[i].chain_length);
+ service_dict->SetInteger("socket_type", layered_providers[i].socket_type);
+ service_dict->SetInteger("socket_protocol",
+ layered_providers[i].socket_protocol);
+ service_dict->SetString("path", layered_providers[i].path);
+
+ layered_provider_list->Append(service_dict);
+ }
+ service_providers->Set("service_providers", layered_provider_list);
+
+ WinsockNamespaceProviderList namespace_providers;
+ GetWinsockNamespaceProviders(&namespace_providers);
+ ListValue* namespace_list = new ListValue;
+ for (size_t i = 0; i < namespace_providers.size(); ++i) {
+ DictionaryValue* namespace_dict = new DictionaryValue();
+ namespace_dict->SetString("name", namespace_providers[i].name);
+ namespace_dict->SetBoolean("active", namespace_providers[i].active);
+ namespace_dict->SetInteger("version", namespace_providers[i].version);
+ namespace_dict->SetInteger("type", namespace_providers[i].type);
+
+ namespace_list->Append(namespace_dict);
+ }
+ service_providers->Set("namespace_providers", namespace_list);
+
+ CallJavascriptFunction(L"g_browser.receivedServiceProviders",
+ service_providers);
+}
+#endif
+
+void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel(
+ const ListValue* list) {
+ int log_level;
+ std::string log_level_string;
+ if (!list->GetString(0, &log_level_string) ||
+ !base::StringToInt(log_level_string, &log_level)) {
+ NOTREACHED();
+ return;
+ }
+
+ DCHECK_GE(log_level, net::NetLog::LOG_ALL);
+ DCHECK_LE(log_level, net::NetLog::LOG_BASIC);
+ SetLogLevel(static_cast<net::NetLog::LogLevel>(log_level));
+}
+
+// Note that unlike other methods of IOThreadImpl, this function
+// can be called from ANY THREAD.
+void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
+ net::NetLog::EventType type,
+ const base::TimeTicks& time,
+ const net::NetLog::Source& source,
+ net::NetLog::EventPhase phase,
+ net::NetLog::EventParameters* params) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this, &IOThreadImpl::AddEntryToQueue,
+ net::NetLog::EntryToDictionaryValue(type, time, source, phase,
+ params, false)));
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::AddEntryToQueue(Value* entry) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!pending_entries_.get()) {
+ pending_entries_.reset(new ListValue());
+ BrowserThread::PostDelayedTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &IOThreadImpl::PostPendingEntries),
+ kNetLogEventDelayMilliseconds);
+ }
+ pending_entries_->Append(entry);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ CallJavascriptFunction(
+ L"g_browser.receivedLogEntries",
+ pending_entries_.release());
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
+ CallJavascriptFunction(L"g_browser.receivedStartConnectionTestSuite", NULL);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment(
+ const ConnectionTester::Experiment& experiment) {
+ CallJavascriptFunction(
+ L"g_browser.receivedStartConnectionTestExperiment",
+ ExperimentToValue(experiment));
+}
+
+void
+NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment(
+ const ConnectionTester::Experiment& experiment,
+ int result) {
+ DictionaryValue* dict = new DictionaryValue();
+
+ dict->Set("experiment", ExperimentToValue(experiment));
+ dict->SetInteger("result", result);
+
+ CallJavascriptFunction(
+ L"g_browser.receivedCompletedConnectionTestExperiment",
+ dict);
+}
+
+void
+NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
+ CallJavascriptFunction(
+ L"g_browser.receivedCompletedConnectionTestSuite",
+ NULL);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::DispatchToMessageHandler(
+ ListValue* arg, MessageHandler method) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ (this->*method)(arg);
+ delete arg;
+}
+
+// Note that this can be called from ANY THREAD.
+void NetInternalsMessageHandler::IOThreadImpl::CallJavascriptFunction(
+ const std::wstring& function_name,
+ Value* arg) {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ if (handler_ && !was_webui_deleted_) {
+ // We check |handler_| in case it was deleted on the UI thread earlier
+ // while we were running on the IO thread.
+ handler_->CallJavascriptFunction(function_name, arg);
+ }
+ delete arg;
+ return;
+ }
+
+ if (!BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &IOThreadImpl::CallJavascriptFunction,
+ function_name, arg))) {
+ // Failed posting the task, avoid leaking.
+ delete arg;
+ }
+}
+
+} // namespace
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NetInternalsUI
+//
+////////////////////////////////////////////////////////////////////////////////
+
+NetInternalsUI::NetInternalsUI(TabContents* contents) : WebUI(contents) {
+ AddMessageHandler((new NetInternalsMessageHandler())->Attach(this));
+
+ NetInternalsHTMLSource* html_source = new NetInternalsHTMLSource();
+
+ // Set up the chrome://net-internals/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
diff --git a/chrome/browser/ui/webui/net_internals_ui.h b/chrome/browser/ui/webui/net_internals_ui.h
new file mode 100644
index 0000000..023d76a
--- /dev/null
+++ b/chrome/browser/ui/webui/net_internals_ui.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_NET_INTERNALS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_NET_INTERNALS_UI_H_
+#pragma once
+
+#include "content/browser/webui/web_ui.h"
+
+class NetInternalsUI : public WebUI {
+ public:
+ explicit NetInternalsUI(TabContents* contents);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NetInternalsUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_NET_INTERNALS_UI_H_
diff --git a/chrome/browser/ui/webui/new_tab_ui.cc b/chrome/browser/ui/webui/new_tab_ui.cc
new file mode 100644
index 0000000..a2e28b7
--- /dev/null
+++ b/chrome/browser/ui/webui/new_tab_ui.cc
@@ -0,0 +1,604 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+
+#include "chrome/browser/ui/webui/new_tab_ui.h"
+
+#include <set>
+
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/i18n/rtl.h"
+#include "base/metrics/histogram.h"
+#include "base/singleton.h"
+#include "base/string_number_conversions.h"
+#include "base/threading/thread.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/sessions/session_types.h"
+#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/sessions/tab_restore_service_observer.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/webui/app_launcher_handler.h"
+#include "chrome/browser/webui/foreign_session_handler.h"
+#include "chrome/browser/webui/most_visited_handler.h"
+#include "chrome/browser/webui/new_tab_page_sync_handler.h"
+#include "chrome/browser/webui/ntp_login_handler.h"
+#include "chrome/browser/webui/ntp_resource_cache.h"
+#include "chrome/browser/webui/shown_sections_handler.h"
+#include "chrome/browser/webui/theme_source.h"
+#include "chrome/browser/webui/tips_handler.h"
+#include "chrome/browser/webui/value_helper.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+// The number of recent bookmarks we show.
+const int kRecentBookmarks = 9;
+
+// The number of search URLs to show.
+const int kSearchURLs = 3;
+
+// The amount of time there must be no painting for us to consider painting
+// finished. Observed times are in the ~1200ms range on Windows.
+const int kTimeoutMs = 2000;
+
+// Strings sent to the page via jstemplates used to set the direction of the
+// HTML document based on locale.
+const char kRTLHtmlTextDirection[] = "rtl";
+const char kDefaultHtmlTextDirection[] = "ltr";
+
+///////////////////////////////////////////////////////////////////////////////
+// RecentlyClosedTabsHandler
+
+class RecentlyClosedTabsHandler : public WebUIMessageHandler,
+ public TabRestoreServiceObserver {
+ public:
+ RecentlyClosedTabsHandler() : tab_restore_service_(NULL) {}
+ virtual ~RecentlyClosedTabsHandler();
+
+ // WebUIMessageHandler implementation.
+ virtual void RegisterMessages();
+
+ // Callback for the "reopenTab" message. Rewrites the history of the
+ // currently displayed tab to be the one in TabRestoreService with a
+ // history of a session passed in through the content pointer.
+ void HandleReopenTab(const ListValue* args);
+
+ // Callback for the "getRecentlyClosedTabs" message.
+ void HandleGetRecentlyClosedTabs(const ListValue* args);
+
+ // Observer callback for TabRestoreServiceObserver. Sends data on
+ // recently closed tabs to the javascript side of this page to
+ // display to the user.
+ virtual void TabRestoreServiceChanged(TabRestoreService* service);
+
+ // Observer callback to notice when our associated TabRestoreService
+ // is destroyed.
+ virtual void TabRestoreServiceDestroyed(TabRestoreService* service);
+
+ private:
+ // TabRestoreService that we are observing.
+ TabRestoreService* tab_restore_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(RecentlyClosedTabsHandler);
+};
+
+void RecentlyClosedTabsHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("getRecentlyClosedTabs",
+ NewCallback(this,
+ &RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs));
+ web_ui_->RegisterMessageCallback("reopenTab",
+ NewCallback(this, &RecentlyClosedTabsHandler::HandleReopenTab));
+}
+
+RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() {
+ if (tab_restore_service_)
+ tab_restore_service_->RemoveObserver(this);
+}
+
+void RecentlyClosedTabsHandler::HandleReopenTab(const ListValue* args) {
+ Browser* browser = Browser::GetBrowserForController(
+ &web_ui_->tab_contents()->controller(), NULL);
+ if (!browser)
+ return;
+
+ int session_to_restore;
+ if (ExtractIntegerValue(args, &session_to_restore))
+ tab_restore_service_->RestoreEntryById(browser, session_to_restore, true);
+ // The current tab has been nuked at this point; don't touch any member
+ // variables.
+}
+
+void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs(
+ const ListValue* args) {
+ if (!tab_restore_service_) {
+ tab_restore_service_ = web_ui_->GetProfile()->GetTabRestoreService();
+
+ // GetTabRestoreService() can return NULL (i.e., when in Off the
+ // Record mode)
+ if (tab_restore_service_) {
+ // This does nothing if the tabs have already been loaded or they
+ // shouldn't be loaded.
+ tab_restore_service_->LoadTabsFromLastSession();
+
+ tab_restore_service_->AddObserver(this);
+ }
+ }
+
+ if (tab_restore_service_)
+ TabRestoreServiceChanged(tab_restore_service_);
+}
+
+void RecentlyClosedTabsHandler::TabRestoreServiceChanged(
+ TabRestoreService* service) {
+ ListValue list_value;
+ NewTabUI::AddRecentlyClosedEntries(service->entries(), &list_value);
+
+ web_ui_->CallJavascriptFunction(L"recentlyClosedTabs", list_value);
+}
+
+void RecentlyClosedTabsHandler::TabRestoreServiceDestroyed(
+ TabRestoreService* service) {
+ tab_restore_service_ = NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MetricsHandler
+
+// Let the page contents record UMA actions. Only use when you can't do it from
+// C++. For example, we currently use it to let the NTP log the postion of the
+// Most Visited or Bookmark the user clicked on, as we don't get that
+// information through RequestOpenURL. You will need to update the metrics
+// dashboard with the action names you use, as our processor won't catch that
+// information (treat it as RecordComputedMetrics)
+class MetricsHandler : public WebUIMessageHandler {
+ public:
+ MetricsHandler() {}
+ virtual ~MetricsHandler() {}
+
+ // WebUIMessageHandler implementation.
+ virtual void RegisterMessages();
+
+ // Callback which records a user action.
+ void HandleMetrics(const ListValue* args);
+
+ // Callback for the "logEventTime" message.
+ void HandleLogEventTime(const ListValue* args);
+
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(MetricsHandler);
+};
+
+void MetricsHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("metrics",
+ NewCallback(this, &MetricsHandler::HandleMetrics));
+
+ web_ui_->RegisterMessageCallback("logEventTime",
+ NewCallback(this, &MetricsHandler::HandleLogEventTime));
+}
+
+void MetricsHandler::HandleMetrics(const ListValue* args) {
+ std::string string_action = WideToUTF8(ExtractStringValue(args));
+ UserMetrics::RecordComputedAction(string_action, web_ui_->GetProfile());
+}
+
+void MetricsHandler::HandleLogEventTime(const ListValue* args) {
+ std::string event_name = WideToUTF8(ExtractStringValue(args));
+ web_ui_->tab_contents()->LogNewTabTime(event_name);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// NewTabPageSetHomePageHandler
+
+// Sets the new tab page as home page when user clicks on "make this my home
+// page" link.
+class NewTabPageSetHomePageHandler : public WebUIMessageHandler {
+ public:
+ NewTabPageSetHomePageHandler() {}
+ virtual ~NewTabPageSetHomePageHandler() {}
+
+ // WebUIMessageHandler implementation.
+ virtual void RegisterMessages();
+
+ // Callback for "setHomePage".
+ void HandleSetHomePage(const ListValue* args);
+
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(NewTabPageSetHomePageHandler);
+};
+
+void NewTabPageSetHomePageHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("setHomePage", NewCallback(
+ this, &NewTabPageSetHomePageHandler::HandleSetHomePage));
+}
+
+void NewTabPageSetHomePageHandler::HandleSetHomePage(
+ const ListValue* args) {
+ web_ui_->GetProfile()->GetPrefs()->SetBoolean(prefs::kHomePageIsNewTabPage,
+ true);
+ ListValue list_value;
+ list_value.Append(new StringValue(
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_HOME_PAGE_SET_NOTIFICATION)));
+ list_value.Append(new StringValue(
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_HOME_PAGE_HIDE_NOTIFICATION)));
+ web_ui_->CallJavascriptFunction(L"onHomePageSet", list_value);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// NewTabPageClosePromoHandler
+
+// Turns off the promo line permanently when it has been explicitly closed by
+// the user.
+class NewTabPageClosePromoHandler : public WebUIMessageHandler {
+ public:
+ NewTabPageClosePromoHandler() {}
+ virtual ~NewTabPageClosePromoHandler() {}
+
+ // WebUIMessageHandler implementation.
+ virtual void RegisterMessages();
+
+ // Callback for "closePromo".
+ void HandleClosePromo(const ListValue* args);
+
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(NewTabPageClosePromoHandler);
+};
+
+void NewTabPageClosePromoHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("closePromo", NewCallback(
+ this, &NewTabPageClosePromoHandler::HandleClosePromo));
+}
+
+void NewTabPageClosePromoHandler::HandleClosePromo(
+ const ListValue* args) {
+ web_ui_->GetProfile()->GetPrefs()->SetBoolean(prefs::kNTPPromoClosed, true);
+ NotificationService* service = NotificationService::current();
+ service->Notify(NotificationType::PROMO_RESOURCE_STATE_CHANGED,
+ Source<NewTabPageClosePromoHandler>(this),
+ NotificationService::NoDetails());
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// NewTabUI
+
+NewTabUI::NewTabUI(TabContents* contents)
+ : WebUI(contents) {
+ // Override some options on the Web UI.
+ hide_favicon_ = true;
+ force_bookmark_bar_visible_ = true;
+ focus_location_bar_by_default_ = true;
+ should_hide_url_ = true;
+ overridden_title_ = l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
+
+ // We count all link clicks as AUTO_BOOKMARK, so that site can be ranked more
+ // highly. Note this means we're including clicks on not only most visited
+ // thumbnails, but also clicks on recently bookmarked.
+ link_transition_type_ = PageTransition::AUTO_BOOKMARK;
+
+ if (NewTabUI::FirstRunDisabled())
+ NewTabHTMLSource::set_first_run(false);
+
+ static bool first_view = true;
+ if (first_view) {
+ first_view = false;
+ }
+
+ if (!GetProfile()->IsOffTheRecord()) {
+ PrefService* pref_service = GetProfile()->GetPrefs();
+ AddMessageHandler((new NTPLoginHandler())->Attach(this));
+ AddMessageHandler((new ShownSectionsHandler(pref_service))->Attach(this));
+ AddMessageHandler((new browser_sync::ForeignSessionHandler())->
+ Attach(this));
+ AddMessageHandler((new MostVisitedHandler())->Attach(this));
+ AddMessageHandler((new RecentlyClosedTabsHandler())->Attach(this));
+ AddMessageHandler((new MetricsHandler())->Attach(this));
+ if (GetProfile()->IsSyncAccessible())
+ AddMessageHandler((new NewTabPageSyncHandler())->Attach(this));
+ ExtensionService* service = GetProfile()->GetExtensionService();
+ // We might not have an ExtensionService (on ChromeOS when not logged in
+ // for example).
+ if (service)
+ AddMessageHandler((new AppLauncherHandler(service))->Attach(this));
+
+ AddMessageHandler((new NewTabPageSetHomePageHandler())->Attach(this));
+ AddMessageHandler((new NewTabPageClosePromoHandler())->Attach(this));
+ }
+
+ // Initializing the CSS and HTML can require some CPU, so do it after
+ // we've hooked up the most visited handler. This allows the DB query
+ // for the new tab thumbs to happen earlier.
+ InitializeCSSCaches();
+ NewTabHTMLSource* html_source =
+ new NewTabHTMLSource(GetProfile()->GetOriginalProfile());
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+
+ // Listen for theme installation.
+ registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
+ NotificationService::AllSources());
+ // Listen for bookmark bar visibility changes.
+ registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
+ NotificationService::AllSources());
+}
+
+NewTabUI::~NewTabUI() {
+}
+
+// The timer callback. If enough time has elapsed since the last paint
+// message, we say we're done painting; otherwise, we keep waiting.
+void NewTabUI::PaintTimeout() {
+ // The amount of time there must be no painting for us to consider painting
+ // finished. Observed times are in the ~1200ms range on Windows.
+ base::TimeTicks now = base::TimeTicks::Now();
+ if ((now - last_paint_) >= base::TimeDelta::FromMilliseconds(kTimeoutMs)) {
+ // Painting has quieted down. Log this as the full time to run.
+ base::TimeDelta load_time = last_paint_ - start_;
+ int load_time_ms = static_cast<int>(load_time.InMilliseconds());
+ NotificationService::current()->Notify(
+ NotificationType::INITIAL_NEW_TAB_UI_LOAD,
+ NotificationService::AllSources(),
+ Details<int>(&load_time_ms));
+ UMA_HISTOGRAM_TIMES("NewTabUI load", load_time);
+ } else {
+ // Not enough quiet time has elapsed.
+ // Some more paints must've occurred since we set the timeout.
+ // Wait some more.
+ timer_.Start(base::TimeDelta::FromMilliseconds(kTimeoutMs), this,
+ &NewTabUI::PaintTimeout);
+ }
+}
+
+void NewTabUI::StartTimingPaint(RenderViewHost* render_view_host) {
+ start_ = base::TimeTicks::Now();
+ last_paint_ = start_;
+ registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DID_PAINT,
+ Source<RenderWidgetHost>(render_view_host));
+ timer_.Start(base::TimeDelta::FromMilliseconds(kTimeoutMs), this,
+ &NewTabUI::PaintTimeout);
+
+}
+void NewTabUI::RenderViewCreated(RenderViewHost* render_view_host) {
+ StartTimingPaint(render_view_host);
+}
+
+void NewTabUI::RenderViewReused(RenderViewHost* render_view_host) {
+ StartTimingPaint(render_view_host);
+}
+
+void NewTabUI::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::BROWSER_THEME_CHANGED: {
+ InitializeCSSCaches();
+ ListValue args;
+ args.Append(Value::CreateStringValue(
+ GetProfile()->GetThemeProvider()->HasCustomImage(
+ IDR_THEME_NTP_ATTRIBUTION) ?
+ "true" : "false"));
+ CallJavascriptFunction(L"themeChanged", args);
+ break;
+ }
+ case NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED: {
+ if (GetProfile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar))
+ CallJavascriptFunction(L"bookmarkBarAttached");
+ else
+ CallJavascriptFunction(L"bookmarkBarDetached");
+ break;
+ }
+ case NotificationType::RENDER_WIDGET_HOST_DID_PAINT: {
+ last_paint_ = base::TimeTicks::Now();
+ break;
+ }
+ default:
+ CHECK(false) << "Unexpected notification: " << type.value;
+ }
+}
+
+void NewTabUI::InitializeCSSCaches() {
+ Profile* profile = GetProfile();
+ ThemeSource* theme = new ThemeSource(profile);
+ profile->GetChromeURLDataManager()->AddDataSource(theme);
+}
+
+// static
+void NewTabUI::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterIntegerPref(prefs::kNTPPrefVersion, 0);
+
+ MostVisitedHandler::RegisterUserPrefs(prefs);
+ ShownSectionsHandler::RegisterUserPrefs(prefs);
+ if (NewTabUI::WebResourcesEnabled())
+ TipsHandler::RegisterUserPrefs(prefs);
+
+ UpdateUserPrefsVersion(prefs);
+}
+
+// static
+bool NewTabUI::UpdateUserPrefsVersion(PrefService* prefs) {
+ const int old_pref_version = prefs->GetInteger(prefs::kNTPPrefVersion);
+ if (old_pref_version != current_pref_version()) {
+ MigrateUserPrefs(prefs, old_pref_version, current_pref_version());
+ prefs->SetInteger(prefs::kNTPPrefVersion, current_pref_version());
+ return true;
+ }
+ return false;
+}
+
+// static
+void NewTabUI::MigrateUserPrefs(PrefService* prefs, int old_pref_version,
+ int new_pref_version) {
+ ShownSectionsHandler::MigrateUserPrefs(prefs, old_pref_version,
+ current_pref_version());
+}
+
+// static
+bool NewTabUI::WebResourcesEnabled() {
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ return !command_line->HasSwitch(switches::kDisableWebResources);
+}
+
+// static
+bool NewTabUI::FirstRunDisabled() {
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ return command_line->HasSwitch(switches::kDisableNewTabFirstRun);
+}
+
+// static
+void NewTabUI::SetURLTitleAndDirection(DictionaryValue* dictionary,
+ const string16& title,
+ const GURL& gurl) {
+ dictionary->SetString("url", gurl.spec());
+
+ bool using_url_as_the_title = false;
+ string16 title_to_set(title);
+ if (title_to_set.empty()) {
+ using_url_as_the_title = true;
+ title_to_set = UTF8ToUTF16(gurl.spec());
+ }
+
+ // We set the "dir" attribute of the title, so that in RTL locales, a LTR
+ // title is rendered left-to-right and truncated from the right. For example,
+ // the title of http://msdn.microsoft.com/en-us/default.aspx is "MSDN:
+ // Microsoft developer network". In RTL locales, in the [New Tab] page, if
+ // the "dir" of this title is not specified, it takes Chrome UI's
+ // directionality. So the title will be truncated as "soft developer
+ // network". Setting the "dir" attribute as "ltr" renders the truncated title
+ // as "MSDN: Microsoft D...". As another example, the title of
+ // http://yahoo.com is "Yahoo!". In RTL locales, in the [New Tab] page, the
+ // title will be rendered as "!Yahoo" if its "dir" attribute is not set to
+ // "ltr".
+ //
+ // Since the title can contain BiDi text, we need to mark the text as either
+ // RTL or LTR, depending on the characters in the string. If we use the URL
+ // as the title, we mark the title as LTR since URLs are always treated as
+ // left to right strings. Simply setting the title's "dir" attribute works
+ // fine for rendering and truncating the title. However, it does not work for
+ // entire title within a tooltip when the mouse is over the title link.. For
+ // example, without LRE-PDF pair, the title "Yahoo!" will be rendered as
+ // "!Yahoo" within the tooltip when the mouse is over the title link.
+ std::string direction = kDefaultHtmlTextDirection;
+ if (base::i18n::IsRTL()) {
+ if (using_url_as_the_title) {
+ base::i18n::WrapStringWithLTRFormatting(&title_to_set);
+ } else {
+ if (base::i18n::StringContainsStrongRTLChars(title)) {
+ base::i18n::WrapStringWithRTLFormatting(&title_to_set);
+ direction = kRTLHtmlTextDirection;
+ } else {
+ base::i18n::WrapStringWithLTRFormatting(&title_to_set);
+ }
+ }
+ }
+ dictionary->SetString("title", title_to_set);
+ dictionary->SetString("direction", direction);
+}
+
+namespace {
+
+bool IsTabUnique(const DictionaryValue* tab,
+ std::set<std::string>* unique_items) {
+ DCHECK(unique_items);
+ std::string title;
+ std::string url;
+ if (tab->GetString("title", &title) &&
+ tab->GetString("url", &url)) {
+ // TODO(viettrungluu): this isn't obviously reliable, since different
+ // combinations of titles/urls may conceivably yield the same string.
+ std::string unique_key = title + url;
+ if (unique_items->find(unique_key) != unique_items->end())
+ return false;
+ else
+ unique_items->insert(unique_key);
+ }
+ return true;
+}
+
+} // namespace
+
+// static
+void NewTabUI::AddRecentlyClosedEntries(
+ const TabRestoreService::Entries& entries, ListValue* entry_list_value) {
+ const int max_count = 10;
+ int added_count = 0;
+ std::set<std::string> unique_items;
+ // We filter the list of recently closed to only show 'interesting' entries,
+ // where an interesting entry is either a closed window or a closed tab
+ // whose selected navigation is not the new tab ui.
+ for (TabRestoreService::Entries::const_iterator it = entries.begin();
+ it != entries.end() && added_count < max_count; ++it) {
+ TabRestoreService::Entry* entry = *it;
+ scoped_ptr<DictionaryValue> entry_dict(new DictionaryValue());
+ if ((entry->type == TabRestoreService::TAB &&
+ ValueHelper::TabToValue(
+ *static_cast<TabRestoreService::Tab*>(entry),
+ entry_dict.get()) &&
+ IsTabUnique(entry_dict.get(), &unique_items)) ||
+ (entry->type == TabRestoreService::WINDOW &&
+ ValueHelper::WindowToValue(
+ *static_cast<TabRestoreService::Window*>(entry),
+ entry_dict.get()))) {
+ entry_dict->SetInteger("sessionId", entry->id);
+ entry_list_value->Append(entry_dict.release());
+ added_count++;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// NewTabHTMLSource
+
+bool NewTabUI::NewTabHTMLSource::first_run_ = true;
+
+NewTabUI::NewTabHTMLSource::NewTabHTMLSource(Profile* profile)
+ : DataSource(chrome::kChromeUINewTabHost, MessageLoop::current()),
+ profile_(profile) {
+}
+
+void NewTabUI::NewTabHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (AppLauncherHandler::HandlePing(profile_, path)) {
+ return;
+ } else if (!path.empty() && path[0] != '#') {
+ // A path under new-tab was requested; it's likely a bad relative
+ // URL from the new tab page, but in any case it's an error.
+ NOTREACHED();
+ return;
+ }
+
+ scoped_refptr<RefCountedBytes> html_bytes(
+ profile_->GetNTPResourceCache()->GetNewTabHTML(is_off_the_record));
+
+ SendResponse(request_id, html_bytes);
+}
+
+std::string NewTabUI::NewTabHTMLSource::GetMimeType(const std::string&) const {
+ return "text/html";
+}
+
+bool NewTabUI::NewTabHTMLSource::ShouldReplaceExistingSource() const {
+ return false;
+}
diff --git a/chrome/browser/ui/webui/new_tab_ui.h b/chrome/browser/ui/webui/new_tab_ui.h
new file mode 100644
index 0000000..005482c
--- /dev/null
+++ b/chrome/browser/ui/webui/new_tab_ui.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_NEW_TAB_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_NEW_TAB_UI_H_
+#pragma once
+
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/timer.h"
+#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "content/browser/webui/web_ui.h"
+
+class GURL;
+class MessageLoop;
+class PrefService;
+class Profile;
+
+// The TabContents used for the New Tab page.
+class NewTabUI : public WebUI,
+ public NotificationObserver {
+ public:
+ explicit NewTabUI(TabContents* manager);
+ ~NewTabUI();
+
+ // Override WebUI methods so we can hook up the paint timer to the render
+ // view host.
+ virtual void RenderViewCreated(RenderViewHost* render_view_host);
+ virtual void RenderViewReused(RenderViewHost* render_view_host);
+
+ static void RegisterUserPrefs(PrefService* prefs);
+ static void MigrateUserPrefs(PrefService* prefs, int old_pref_version,
+ int new_pref_version);
+
+ // Whether we should disable the web resources backend service
+ static bool WebResourcesEnabled();
+
+ // Whether we should disable the first run notification based on the command
+ // line switch.
+ static bool FirstRunDisabled();
+
+ // Adds "url", "title", and "direction" keys on incoming dictionary, setting
+ // title as the url as a fallback on empty title.
+ static void SetURLTitleAndDirection(DictionaryValue* dictionary,
+ const string16& title,
+ const GURL& gurl);
+
+ // Converts a list of TabRestoreService entries to the JSON format required
+ // by the NTP and adds them to the given list value.
+ static void AddRecentlyClosedEntries(
+ const TabRestoreService::Entries& entries,
+ ListValue* entry_list_value);
+
+ // The current preference version.
+ static int current_pref_version() { return current_pref_version_; }
+
+ class NewTabHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ explicit NewTabHTMLSource(Profile* profile);
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+
+ virtual std::string GetMimeType(const std::string&) const;
+
+ virtual bool ShouldReplaceExistingSource() const;
+
+ // Setters and getters for first_run.
+ static void set_first_run(bool first_run) { first_run_ = first_run; }
+ static bool first_run() { return first_run_; }
+
+ private:
+ virtual ~NewTabHTMLSource() {}
+
+ // Whether this is the first run.
+ static bool first_run_;
+
+ // Pointer back to the original profile.
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(NewTabHTMLSource);
+ };
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(NewTabUITest, UpdateUserPrefsVersion);
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Reset the CSS caches.
+ void InitializeCSSCaches();
+
+ void StartTimingPaint(RenderViewHost* render_view_host);
+ void PaintTimeout();
+
+ // Updates the user prefs version and calls |MigrateUserPrefs| if needed.
+ // Returns true if the version was updated.
+ static bool UpdateUserPrefsVersion(PrefService* prefs);
+
+ NotificationRegistrar registrar_;
+
+ // The time when we started benchmarking.
+ base::TimeTicks start_;
+ // The last time we got a paint notification.
+ base::TimeTicks last_paint_;
+ // Scoping so we can be sure our timeouts don't outlive us.
+ base::OneShotTimer<NewTabUI> timer_;
+ // The preference version. This used for migrating prefs of the NTP.
+ static const int current_pref_version_ = 3;
+
+ DISALLOW_COPY_AND_ASSIGN(NewTabUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_NEW_TAB_UI_H_
diff --git a/chrome/browser/ui/webui/new_tab_ui_uitest.cc b/chrome/browser/ui/webui/new_tab_ui_uitest.cc
new file mode 100644
index 0000000..3164fb6
--- /dev/null
+++ b/chrome/browser/ui/webui/new_tab_ui_uitest.cc
@@ -0,0 +1,183 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/ui/ui_test.h"
+
+#include "base/test/test_timeouts.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/prefs/pref_value_store.h"
+#include "chrome/browser/sync/signin_manager.h"
+#include "chrome/browser/ui/webui/new_tab_ui.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/json_pref_store.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "chrome/test/automation/window_proxy.h"
+#include "chrome/test/testing_pref_service.h"
+
+class NewTabUITest : public UITest {
+ public:
+ NewTabUITest() {
+ dom_automation_enabled_ = true;
+ // Set home page to the empty string so that we can set the home page using
+ // preferences.
+ set_homepage("");
+
+ // Setup the DEFAULT_THEME profile (has fake history entries).
+ set_template_user_data(UITest::ComputeTypicalUserDataSource(
+ ProxyLauncher::DEFAULT_THEME));
+ }
+};
+
+TEST_F(NewTabUITest, NTPHasThumbnails) {
+ // Switch to the "new tab" tab, which should be any new tab after the
+ // first (the first is about:blank).
+ scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ // Bring up a new tab page.
+ ASSERT_TRUE(window->RunCommand(IDC_NEW_TAB));
+
+ scoped_refptr<TabProxy> tab = window->GetActiveTab();
+ ASSERT_TRUE(tab.get());
+
+ // TopSites should return at least 3 non-filler pages.
+ // 8 - 3 = max 5 filler pages.
+ ASSERT_TRUE(WaitUntilJavaScriptCondition(tab, L"",
+ L"window.domAutomationController.send("
+ L"document.getElementsByClassName('filler').length <= 5)",
+ TestTimeouts::action_max_timeout_ms()));
+}
+
+// Sometimes hangs: http://crbug.com/70157
+TEST_F(NewTabUITest, DISABLED_NTPHasLoginName) {
+ scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ ASSERT_TRUE(window->SetStringPreference(prefs::kGoogleServicesUsername,
+ "user@gmail.com"));
+ // Bring up a new tab page.
+ ASSERT_TRUE(window->RunCommand(IDC_NEW_TAB));
+
+ scoped_refptr<TabProxy> tab = window->GetActiveTab();
+ ASSERT_TRUE(tab.get());
+
+ std::wstring displayed_username;
+ // The login span should be eventually populated and have the
+ // correct value.
+ ASSERT_TRUE(WaitUntilJavaScriptCondition(tab, L"",
+ L"window.domAutomationController.send("
+ L"document.getElementById('login-username').innerText.length > 0)",
+ TestTimeouts::action_max_timeout_ms()));
+
+ ASSERT_TRUE(tab->ExecuteAndExtractString(
+ L"",
+ L"window.domAutomationController.send("
+ L"document.getElementById('login-username').innerText)",
+ &displayed_username));
+
+ EXPECT_EQ(L"user@gmail.com", displayed_username);
+}
+
+// Loads about:hang into two NTP tabs, ensuring we don't crash.
+// See http://crbug.com/59859.
+TEST_F(NewTabUITest, AboutHangInNTP) {
+ scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ // Bring up a new tab page.
+ ASSERT_TRUE(window->RunCommand(IDC_NEW_TAB));
+ scoped_refptr<TabProxy> tab = window->GetActiveTab();
+ ASSERT_TRUE(tab.get());
+
+ // Navigate to about:hang to stall the process.
+ ASSERT_TRUE(tab->NavigateToURLAsync(GURL(chrome::kAboutHangURL)));
+
+ // Visit about:hang again in another NTP. Don't bother waiting for the
+ // NTP to load, because it's hung.
+ ASSERT_TRUE(window->RunCommandAsync(IDC_NEW_TAB));
+ scoped_refptr<TabProxy> tab2 = window->GetActiveTab();
+ ASSERT_TRUE(tab2.get());
+ ASSERT_TRUE(tab2->NavigateToURLAsync(GURL(chrome::kAboutHangURL)));
+}
+
+// Allows testing NTP in process-per-tab mode.
+class NewTabUIProcessPerTabTest : public NewTabUITest {
+ public:
+ NewTabUIProcessPerTabTest() : NewTabUITest() {}
+
+ protected:
+ virtual void SetUp() {
+ launch_arguments_.AppendSwitch(switches::kProcessPerTab);
+ UITest::SetUp();
+ }
+};
+
+// Navigates away from NTP before it commits, in process-per-tab mode.
+// Ensures that we don't load the normal page in the NTP process (and thus
+// crash), as in http://crbug.com/69224.
+TEST_F(NewTabUIProcessPerTabTest, NavBeforeNTPCommits) {
+ scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ // Bring up a new tab page.
+ ASSERT_TRUE(window->RunCommand(IDC_NEW_TAB));
+ scoped_refptr<TabProxy> tab = window->GetActiveTab();
+ ASSERT_TRUE(tab.get());
+
+ // Navigate to about:hang to stall the process.
+ ASSERT_TRUE(tab->NavigateToURLAsync(GURL(chrome::kAboutHangURL)));
+
+ // Visit a normal URL in another NTP that hasn't committed.
+ ASSERT_TRUE(window->RunCommandAsync(IDC_NEW_TAB));
+ scoped_refptr<TabProxy> tab2 = window->GetActiveTab();
+ ASSERT_TRUE(tab2.get());
+ ASSERT_TRUE(tab2->NavigateToURL(GURL("data:text/html,hello world")));
+}
+
+// Fails about ~5% of the time on all platforms. http://crbug.com/45001
+TEST_F(NewTabUITest, FLAKY_ChromeInternalLoadsNTP) {
+ scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ // Go to the "new tab page" using its old url, rather than chrome://newtab.
+ scoped_refptr<TabProxy> tab = window->GetTab(0);
+ ASSERT_TRUE(tab.get());
+ ASSERT_TRUE(tab->NavigateToURLAsync(GURL("chrome-internal:")));
+ int load_time;
+ ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));
+
+ // Ensure there are some thumbnails loaded in the page.
+ int thumbnails_count = -1;
+ ASSERT_TRUE(tab->ExecuteAndExtractInt(L"",
+ L"window.domAutomationController.send("
+ L"document.getElementsByClassName('thumbnail-container').length)",
+ &thumbnails_count));
+ EXPECT_GT(thumbnails_count, 0);
+}
+
+TEST_F(NewTabUITest, UpdateUserPrefsVersion) {
+ // PrefService with JSON user-pref file only, no enforced or advised prefs.
+ scoped_ptr<PrefService> prefs(new TestingPrefService);
+
+ // Does the migration
+ NewTabUI::RegisterUserPrefs(prefs.get());
+
+ ASSERT_EQ(NewTabUI::current_pref_version(),
+ prefs->GetInteger(prefs::kNTPPrefVersion));
+
+ // Reset the version
+ prefs->ClearPref(prefs::kNTPPrefVersion);
+ ASSERT_EQ(0, prefs->GetInteger(prefs::kNTPPrefVersion));
+
+ bool migrated = NewTabUI::UpdateUserPrefsVersion(prefs.get());
+ ASSERT_TRUE(migrated);
+ ASSERT_EQ(NewTabUI::current_pref_version(),
+ prefs->GetInteger(prefs::kNTPPrefVersion));
+
+ migrated = NewTabUI::UpdateUserPrefsVersion(prefs.get());
+ ASSERT_FALSE(migrated);
+}
diff --git a/chrome/browser/ui/webui/plugins_ui.cc b/chrome/browser/ui/webui/plugins_ui.cc
new file mode 100644
index 0000000..fed678c
--- /dev/null
+++ b/chrome/browser/ui/webui/plugins_ui.cc
@@ -0,0 +1,374 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/plugins_ui.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/singleton.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/plugin_updater.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pepper_plugin_registry.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "webkit/plugins/npapi/plugin_list.h"
+
+namespace {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// PluginsHTMLSource
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class PluginsUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ PluginsUIHTMLSource()
+ : DataSource(chrome::kChromeUIPluginsHost, MessageLoop::current()) {}
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ ~PluginsUIHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(PluginsUIHTMLSource);
+};
+
+void PluginsUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ // Strings used in the JsTemplate file.
+ DictionaryValue localized_strings;
+ localized_strings.SetString("pluginsTitle",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_TITLE));
+ localized_strings.SetString("pluginsDetailsModeLink",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DETAILS_MODE_LINK));
+ localized_strings.SetString("pluginsNoneInstalled",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_NONE_INSTALLED));
+ localized_strings.SetString("pluginDisabled",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_PLUGIN));
+ localized_strings.SetString("pluginDisabledByPolicy",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN));
+ localized_strings.SetString("pluginCannotBeEnabledDueToPolicy",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_CANNOT_ENABLE_DUE_TO_POLICY));
+ localized_strings.SetString("pluginDownload",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DOWNLOAD));
+ localized_strings.SetString("pluginName",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_NAME));
+ localized_strings.SetString("pluginVersion",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_VERSION));
+ localized_strings.SetString("pluginDescription",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DESCRIPTION));
+ localized_strings.SetString("pluginPath",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_PATH));
+ localized_strings.SetString("pluginMimeTypes",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES));
+ localized_strings.SetString("pluginMimeTypesMimeType",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_MIME_TYPE));
+ localized_strings.SetString("pluginMimeTypesDescription",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_DESCRIPTION));
+ localized_strings.SetString("pluginMimeTypesFileExtensions",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS));
+ localized_strings.SetString("disable",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLE));
+ localized_strings.SetString("enable",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_ENABLE));
+
+ ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece plugins_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_PLUGINS_HTML));
+ std::string full_html(plugins_html.data(), plugins_html.size());
+ jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
+ jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
+ jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
+ jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// PluginsDOMHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// The handler for Javascript messages for the chrome://plugins/ page.
+// TODO(viettrungluu): Make plugin list updates notify, and then observe
+// changes; maybe replumb plugin list through plugin service?
+// <http://crbug.com/39101>
+class PluginsDOMHandler : public WebUIMessageHandler,
+ public NotificationObserver {
+ public:
+ explicit PluginsDOMHandler();
+ virtual ~PluginsDOMHandler() {}
+
+ // WebUIMessageHandler implementation.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+ virtual void RegisterMessages();
+
+ // Callback for the "requestPluginsData" message.
+ void HandleRequestPluginsData(const ListValue* args);
+
+ // Callback for the "enablePlugin" message.
+ void HandleEnablePluginMessage(const ListValue* args);
+
+ // Callback for the "showTermsOfService" message. This really just opens a new
+ // window with about:terms. Flash can't link directly to about:terms due to
+ // the security model.
+ void HandleShowTermsOfServiceMessage(const ListValue* args);
+
+ // Callback for the "saveShowDetailsToPrefs" message.
+ void HandleSaveShowDetailsToPrefs(const ListValue* args);
+
+ // Calback for the "getShowDetails" message.
+ void HandleGetShowDetails(const ListValue* args);
+
+ // NotificationObserver method overrides
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // This extra wrapper is used to ensure we don't leak the ListValue* pointer
+ // if the PluginsDOMHandler object goes away before the task on the UI thread
+ // to give it the plugin list runs.
+ struct ListWrapper {
+ ListValue* list;
+ };
+ // Loads the plugins on the FILE thread.
+ static void LoadPluginsOnFileThread(ListWrapper* wrapper, Task* task);
+
+ // Used in conjunction with ListWrapper to avoid any memory leaks.
+ static void EnsureListDeleted(ListWrapper* wrapper);
+
+ // Call this to start getting the plugins on the UI thread.
+ void LoadPlugins();
+
+ // Called on the UI thread when the plugin information is ready.
+ void PluginsLoaded(ListWrapper* wrapper);
+
+ NotificationRegistrar registrar_;
+
+ ScopedRunnableMethodFactory<PluginsDOMHandler> get_plugins_factory_;
+
+ // This pref guards the value whether about:plugins is in the details mode or
+ // not.
+ BooleanPrefMember show_details_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginsDOMHandler);
+};
+
+PluginsDOMHandler::PluginsDOMHandler()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(get_plugins_factory_(this)) {
+ registrar_.Add(this,
+ NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
+ NotificationService::AllSources());
+}
+
+WebUIMessageHandler* PluginsDOMHandler::Attach(WebUI* web_ui) {
+ PrefService* prefs = web_ui->GetProfile()->GetPrefs();
+
+ show_details_.Init(prefs::kPluginsShowDetails, prefs, this);
+
+ return WebUIMessageHandler::Attach(web_ui);
+}
+
+void PluginsDOMHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("requestPluginsData",
+ NewCallback(this, &PluginsDOMHandler::HandleRequestPluginsData));
+ web_ui_->RegisterMessageCallback("enablePlugin",
+ NewCallback(this, &PluginsDOMHandler::HandleEnablePluginMessage));
+ web_ui_->RegisterMessageCallback("showTermsOfService",
+ NewCallback(this, &PluginsDOMHandler::HandleShowTermsOfServiceMessage));
+ web_ui_->RegisterMessageCallback("saveShowDetailsToPrefs",
+ NewCallback(this, &PluginsDOMHandler::HandleSaveShowDetailsToPrefs));
+ web_ui_->RegisterMessageCallback("getShowDetails",
+ NewCallback(this, &PluginsDOMHandler::HandleGetShowDetails));
+}
+
+void PluginsDOMHandler::HandleRequestPluginsData(const ListValue* args) {
+ LoadPlugins();
+}
+
+void PluginsDOMHandler::HandleEnablePluginMessage(const ListValue* args) {
+ // Be robust in accepting badness since plug-ins display HTML (hence
+ // JavaScript).
+ if (args->GetSize() != 3)
+ return;
+
+ std::string enable_str;
+ std::string is_group_str;
+ if (!args->GetString(1, &enable_str) || !args->GetString(2, &is_group_str))
+ return;
+ bool enable = enable_str == "true";
+
+ PluginUpdater* plugin_updater = PluginUpdater::GetInstance();
+ if (is_group_str == "true") {
+ string16 group_name;
+ if (!args->GetString(0, &group_name))
+ return;
+
+ plugin_updater->EnablePluginGroup(enable, group_name);
+ if (enable) {
+ // See http://crbug.com/50105 for background.
+ string16 adobereader = ASCIIToUTF16(
+ webkit::npapi::PluginGroup::kAdobeReaderGroupName);
+ string16 internalpdf = ASCIIToUTF16(PepperPluginRegistry::kPDFPluginName);
+ if (group_name == adobereader) {
+ plugin_updater->EnablePluginGroup(false, internalpdf);
+ } else if (group_name == internalpdf) {
+ plugin_updater->EnablePluginGroup(false, adobereader);
+ }
+ }
+ } else {
+ FilePath::StringType file_path;
+ if (!args->GetString(0, &file_path))
+ return;
+
+ plugin_updater->EnablePlugin(enable, file_path);
+ }
+
+ // TODO(viettrungluu): We might also want to ensure that the plugins
+ // list is always written to prefs even when the user hasn't disabled a
+ // plugin. <http://crbug.com/39101>
+ plugin_updater->UpdatePreferences(web_ui_->GetProfile(), 0);
+}
+
+void PluginsDOMHandler::HandleShowTermsOfServiceMessage(const ListValue* args) {
+ // Show it in a new browser window....
+ Browser* browser = Browser::Create(web_ui_->GetProfile());
+ browser->OpenURL(GURL(chrome::kAboutTermsURL),
+ GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
+ browser->window()->Show();
+}
+
+void PluginsDOMHandler::HandleSaveShowDetailsToPrefs(const ListValue* args) {
+ std::string details_mode;
+ if (!args->GetString(0, &details_mode)) {
+ NOTREACHED();
+ return;
+ }
+ show_details_.SetValue(details_mode == "true");
+}
+
+void PluginsDOMHandler::HandleGetShowDetails(const ListValue* args) {
+ FundamentalValue show_details(show_details_.GetValue());
+ web_ui_->CallJavascriptFunction(L"loadShowDetailsFromPrefs", show_details);
+}
+
+void PluginsDOMHandler::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(NotificationType::PLUGIN_ENABLE_STATUS_CHANGED, type.value);
+ LoadPlugins();
+}
+
+void PluginsDOMHandler::LoadPluginsOnFileThread(ListWrapper* wrapper,
+ Task* task) {
+ wrapper->list = PluginUpdater::GetInstance()->GetPluginGroupsData();
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ NewRunnableFunction(&PluginsDOMHandler::EnsureListDeleted, wrapper));
+}
+
+void PluginsDOMHandler::EnsureListDeleted(ListWrapper* wrapper) {
+ delete wrapper->list;
+ delete wrapper;
+}
+
+void PluginsDOMHandler::LoadPlugins() {
+ if (!get_plugins_factory_.empty())
+ return;
+
+ ListWrapper* wrapper = new ListWrapper;
+ wrapper->list = NULL;
+ Task* task = get_plugins_factory_.NewRunnableMethod(
+ &PluginsDOMHandler::PluginsLoaded, wrapper);
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ NewRunnableFunction(
+ &PluginsDOMHandler::LoadPluginsOnFileThread, wrapper, task));
+}
+
+void PluginsDOMHandler::PluginsLoaded(ListWrapper* wrapper) {
+ DictionaryValue results;
+ results.Set("plugins", wrapper->list);
+ wrapper->list = NULL; // So it doesn't get deleted.
+ web_ui_->CallJavascriptFunction(L"returnPluginsData", results);
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// PluginsUI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+PluginsUI::PluginsUI(TabContents* contents) : WebUI(contents) {
+ AddMessageHandler((new PluginsDOMHandler())->Attach(this));
+
+ PluginsUIHTMLSource* html_source = new PluginsUIHTMLSource();
+
+ // Set up the chrome://plugins/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+
+// static
+RefCountedMemory* PluginsUI::GetFaviconResourceBytes() {
+ return ResourceBundle::GetSharedInstance().
+ LoadDataResourceBytes(IDR_PLUGIN);
+}
+
+// static
+void PluginsUI::RegisterUserPrefs(PrefService* prefs) {
+ FilePath internal_dir;
+ PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir);
+ prefs->RegisterFilePathPref(prefs::kPluginsLastInternalDirectory,
+ internal_dir);
+
+ prefs->RegisterListPref(prefs::kPluginsPluginsBlacklist);
+ prefs->RegisterListPref(prefs::kPluginsPluginsList);
+ prefs->RegisterBooleanPref(prefs::kPluginsEnabledInternalPDF, false);
+ prefs->RegisterBooleanPref(prefs::kPluginsShowDetails, false);
+ prefs->RegisterBooleanPref(prefs::kPluginsShowSetReaderDefaultInfobar, true);
+}
diff --git a/chrome/browser/ui/webui/plugins_ui.h b/chrome/browser/ui/webui/plugins_ui.h
new file mode 100644
index 0000000..752e639
--- /dev/null
+++ b/chrome/browser/ui/webui/plugins_ui.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_PLUGINS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_PLUGINS_UI_H_
+#pragma once
+
+#include "content/browser/webui/web_ui.h"
+
+class PrefService;
+class RefCountedMemory;
+
+class PluginsUI : public WebUI {
+ public:
+ explicit PluginsUI(TabContents* contents);
+
+ static RefCountedMemory* GetFaviconResourceBytes();
+ static void RegisterUserPrefs(PrefService* prefs);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PluginsUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_PLUGINS_UI_H_
diff --git a/chrome/browser/ui/webui/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview_ui.cc
new file mode 100644
index 0000000..8cb2212
--- /dev/null
+++ b/chrome/browser/ui/webui/print_preview_ui.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/print_preview_ui.h"
+
+#include "base/values.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/webui/print_preview_ui_html_source.h"
+#include "chrome/browser/webui/print_preview_handler.h"
+
+PrintPreviewUI::PrintPreviewUI(TabContents* contents)
+ : WebUI(contents),
+ html_source_(new PrintPreviewUIHTMLSource()) {
+ // PrintPreviewUI owns |handler|.
+ PrintPreviewHandler* handler = new PrintPreviewHandler();
+ AddMessageHandler(handler->Attach(this));
+
+ // Set up the chrome://print/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source_);
+}
+
+PrintPreviewUI::~PrintPreviewUI() {
+}
+
+PrintPreviewUIHTMLSource* PrintPreviewUI::html_source() {
+ return html_source_.get();
+}
+
+void PrintPreviewUI::PreviewDataIsAvailable(int expected_pages_count) {
+ StringValue dummy_url("chrome://print/print.pdf");
+ FundamentalValue pages_count(expected_pages_count);
+ CallJavascriptFunction(L"createPDFPlugin", dummy_url, pages_count);
+}
diff --git a/chrome/browser/ui/webui/print_preview_ui.h b/chrome/browser/ui/webui/print_preview_ui.h
new file mode 100644
index 0000000..b4a62cf
--- /dev/null
+++ b/chrome/browser/ui/webui/print_preview_ui.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_UI_H_
+#pragma once
+
+#include "base/ref_counted.h"
+#include "content/browser/webui/web_ui.h"
+
+class PrintPreviewUIHTMLSource;
+
+class PrintPreviewUI : public WebUI {
+ public:
+ explicit PrintPreviewUI(TabContents* contents);
+ virtual ~PrintPreviewUI();
+
+ PrintPreviewUIHTMLSource* html_source();
+
+ // Notify the Web UI renderer that preview data is available.
+ // |expected_pages_count| specifies the total number of pages.
+ void PreviewDataIsAvailable(int expected_pages_count);
+
+ private:
+ scoped_refptr<PrintPreviewUIHTMLSource> html_source_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrintPreviewUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_UI_H_
diff --git a/chrome/browser/ui/webui/print_preview_ui_html_source.cc b/chrome/browser/ui/webui/print_preview_ui_html_source.cc
new file mode 100644
index 0000000..9e37c64
--- /dev/null
+++ b/chrome/browser/ui/webui/print_preview_ui_html_source.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/print_preview_ui_html_source.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/message_loop.h"
+#include "base/shared_memory.h"
+#include "base/string_piece.h"
+#include "base/values.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+void SetLocalizedStrings(DictionaryValue* localized_strings) {
+ localized_strings->SetString(std::string("title"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_TITLE));
+ localized_strings->SetString(std::string("loading"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_LOADING));
+ localized_strings->SetString(std::string("noPlugin"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_NO_PLUGIN));
+ localized_strings->SetString(std::string("noPrinter"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_NO_PRINTER));
+
+ localized_strings->SetString(std::string("printButton"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_PRINT_BUTTON));
+ localized_strings->SetString(std::string("cancelButton"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_CANCEL_BUTTON));
+
+ localized_strings->SetString(std::string("optionAllPages"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_OPTION_ALL_PAGES));
+ localized_strings->SetString(std::string("optionBw"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_OPTION_BW));
+ localized_strings->SetString(std::string("optionCollate"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_OPTION_COLLATE));
+ localized_strings->SetString(std::string("optionColor"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_OPTION_COLOR));
+ localized_strings->SetString(std::string("optionLandscape"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_OPTION_LANDSCAPE));
+ localized_strings->SetString(std::string("optionPortrait"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_OPTION_PORTRAIT));
+ localized_strings->SetString(std::string("optionTwoSided"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_OPTION_TWO_SIDED));
+}
+
+} // namespace
+
+PrintPreviewUIHTMLSource::PrintPreviewUIHTMLSource()
+ : DataSource(chrome::kChromeUIPrintHost, MessageLoop::current()),
+ data_(std::make_pair(static_cast<base::SharedMemory*>(NULL), 0U)) {
+}
+
+PrintPreviewUIHTMLSource::~PrintPreviewUIHTMLSource() {
+ delete data_.first;
+}
+
+void PrintPreviewUIHTMLSource::GetPrintPreviewData(PrintPreviewData* data) {
+ *data = data_;
+}
+
+void PrintPreviewUIHTMLSource::SetPrintPreviewData(
+ const PrintPreviewData& data) {
+ delete data_.first;
+ data_ = data;
+}
+
+void PrintPreviewUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ if (path.empty()) {
+ // Print Preview Index page.
+ DictionaryValue localized_strings;
+ SetLocalizedStrings(&localized_strings);
+ SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece print_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_PRINT_PREVIEW_HTML));
+ const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
+ print_html, &localized_strings);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+ return;
+ } else if (path == "print.pdf" && data_.first) {
+ // Print Preview data.
+ char* preview_data = reinterpret_cast<char*>(data_.first->memory());
+ uint32 preview_data_size = data_.second;
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(preview_data_size);
+ std::vector<unsigned char>::iterator it = html_bytes->data.begin();
+ for (uint32 i = 0; i < preview_data_size; ++i, ++it)
+ *it = *(preview_data + i);
+ SendResponse(request_id, html_bytes);
+ return;
+ } else {
+ // Invalid request.
+ scoped_refptr<RefCountedBytes> empty_bytes(new RefCountedBytes);
+ SendResponse(request_id, empty_bytes);
+ return;
+ }
+}
+
+std::string PrintPreviewUIHTMLSource::GetMimeType(
+ const std::string& path) const {
+ // Print Preview Index page.
+ if (path.empty())
+ return "text/html";
+ // Print Preview data.
+ return "application/pdf";
+}
diff --git a/chrome/browser/ui/webui/print_preview_ui_html_source.h b/chrome/browser/ui/webui/print_preview_ui_html_source.h
new file mode 100644
index 0000000..2f9f8b8
--- /dev/null
+++ b/chrome/browser/ui/webui/print_preview_ui_html_source.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_UI_HTML_SOURCE_H_
+#define CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_UI_HTML_SOURCE_H_
+#pragma once
+
+#include <string>
+#include <utility>
+
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+
+namespace base {
+class SharedMemory;
+}
+
+class PrintPreviewUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ // A SharedMemory that contains the data for print preview,
+ // and the size of the print preview data in bytes.
+ typedef std::pair<base::SharedMemory*, uint32> PrintPreviewData;
+
+ PrintPreviewUIHTMLSource();
+ virtual ~PrintPreviewUIHTMLSource();
+
+ // Gets the print preview |data|. The data is valid as long as the
+ // PrintPreviewHandler is valid and SetPrintPreviewData() does not get called.
+ void GetPrintPreviewData(PrintPreviewData* data);
+
+ // Sets the print preview |data|. PrintPreviewHandler owns the data and is
+ // responsible for freeing it when either:
+ // a) there is new data.
+ // b) when PrintPreviewHandler is destroyed.
+ void SetPrintPreviewData(const PrintPreviewData& data);
+
+ // ChromeURLDataManager::DataSource implementation.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const;
+
+ private:
+ // Current print preview data, the contents of which are owned by
+ // PrintPreviewHandler.
+ PrintPreviewData data_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrintPreviewUIHTMLSource);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_UI_HTML_SOURCE_H_
diff --git a/chrome/browser/ui/webui/print_preview_ui_html_source_unittest.cc b/chrome/browser/ui/webui/print_preview_ui_html_source_unittest.cc
new file mode 100644
index 0000000..eb0d123
--- /dev/null
+++ b/chrome/browser/ui/webui/print_preview_ui_html_source_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "base/shared_memory.h"
+#include "chrome/browser/printing/print_preview_tab_controller.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/webui/print_preview_ui.h"
+#include "chrome/browser/ui/webui/print_preview_ui_html_source.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/browser_with_test_window_test.h"
+#include "chrome/test/testing_profile.h"
+
+typedef BrowserWithTestWindowTest PrintPreviewUIHTMLSourceTest;
+
+// Create/Get a preview tab for initiator tab.
+TEST_F(PrintPreviewUIHTMLSourceTest, PrintPreviewData) {
+ // TODO(thestig) Remove when print preview is enabled by default.
+ CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnablePrintPreview);
+ ASSERT_TRUE(browser());
+ BrowserList::SetLastActive(browser());
+ ASSERT_TRUE(BrowserList::GetLastActive());
+
+ browser()->NewTab();
+ TabContents* initiator_tab = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(initiator_tab);
+
+ scoped_refptr<printing::PrintPreviewTabController>
+ controller(new printing::PrintPreviewTabController());
+ ASSERT_TRUE(controller);
+
+ TabContents* preview_tab = controller->GetOrCreatePreviewTab(
+ initiator_tab, initiator_tab->controller().window_id().id());
+
+ EXPECT_NE(initiator_tab, preview_tab);
+ EXPECT_EQ(2, browser()->tab_count());
+
+ PrintPreviewUI* preview_ui =
+ reinterpret_cast<PrintPreviewUI*>(preview_tab->web_ui());
+ ASSERT_TRUE(preview_ui != NULL);
+ PrintPreviewUIHTMLSource* html_source = preview_ui->html_source();
+
+ PrintPreviewUIHTMLSource::PrintPreviewData data;
+ html_source->GetPrintPreviewData(&data);
+ EXPECT_EQ(NULL, data.first);
+ EXPECT_EQ(0U, data.second);
+
+ PrintPreviewUIHTMLSource::PrintPreviewData dummy_data =
+ std::make_pair(new base::SharedMemory(), 1234);
+
+ html_source->SetPrintPreviewData(dummy_data);
+ html_source->GetPrintPreviewData(&data);
+ EXPECT_EQ(dummy_data, data);
+
+ // This should not cause any memory leaks.
+ dummy_data.first = new base::SharedMemory();
+ html_source->SetPrintPreviewData(dummy_data);
+}
diff --git a/chrome/browser/ui/webui/print_preview_ui_uitest.cc b/chrome/browser/ui/webui/print_preview_ui_uitest.cc
new file mode 100644
index 0000000..d53cf33
--- /dev/null
+++ b/chrome/browser/ui/webui/print_preview_ui_uitest.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "chrome/test/ui/ui_test.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+class PrintPreviewUITest : public UITest {
+ public:
+ PrintPreviewUITest() {
+ dom_automation_enabled_ = true;
+ // TODO(thestig): Remove when print preview is enabled by default.
+ launch_arguments_.AppendSwitch(switches::kEnablePrintPreview);
+ }
+
+ void AssertIsPrintPage(TabProxy* tab) {
+ std::wstring title;
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ string16 expected_title =
+ l10n_util::GetStringUTF16(IDS_PRINT_PREVIEW_TITLE);
+ ASSERT_EQ(expected_title, WideToUTF16Hack(title));
+ }
+};
+
+// TODO(thestig) Remove this test in the future if loading
+// chrome::kChromeUIPrintURL directly does not make sense.
+TEST_F(PrintPreviewUITest, LoadPrintPreviewByURL) {
+ scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+
+ scoped_refptr<TabProxy> tab = browser->GetActiveTab();
+ ASSERT_TRUE(tab.get());
+
+ // Go to the print preview tab via URL.
+ NavigateToURL(GURL(chrome::kChromeUIPrintURL));
+ AssertIsPrintPage(tab);
+}
+
+TEST_F(PrintPreviewUITest, PrintCommandDisabled) {
+ scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+
+ // Go to the about:blank page.
+ NavigateToURL(GURL(chrome::kAboutBlankURL));
+
+ // Make sure there is 1 tab and print is enabled. Create print preview tab.
+ int tab_count;
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ bool enabled;
+ ASSERT_TRUE(browser->IsMenuCommandEnabled(IDC_PRINT, &enabled));
+ ASSERT_TRUE(enabled);
+ ASSERT_TRUE(browser->RunCommand(IDC_PRINT));
+
+ // Make sure there are 2 tabs and print is disabled.
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+ scoped_refptr<TabProxy> tab = browser->GetActiveTab();
+ ASSERT_TRUE(tab.get());
+ AssertIsPrintPage(tab);
+ ASSERT_TRUE(browser->IsMenuCommandEnabled(IDC_PRINT, &enabled));
+ ASSERT_FALSE(enabled);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/webui/remoting_ui.cc b/chrome/browser/ui/webui/remoting_ui.cc
new file mode 100644
index 0000000..654894a
--- /dev/null
+++ b/chrome/browser/ui/webui/remoting_ui.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/remoting_ui.h"
+
+#include "base/singleton.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/common/url_constants.h"
+#include "grit/theme_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// RemotingHTMLSource
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class RemotingUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ RemotingUIHTMLSource()
+ : DataSource(chrome::kChromeUIRemotingHost, MessageLoop::current()) {}
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "pepper-application/x-chromoting";
+ }
+
+ private:
+ ~RemotingUIHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(RemotingUIHTMLSource);
+};
+
+void RemotingUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ // Dummy data. Not used, but we need to send something back in the response.
+ std::string full_html = "remoting";
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes());
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// RemotingUI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+RemotingUI::RemotingUI(TabContents* contents) : WebUI(contents) {
+ RemotingUIHTMLSource* html_source = new RemotingUIHTMLSource();
+
+ // Set up the chrome://remoting source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
+
+
+// static
+RefCountedMemory* RemotingUI::GetFaviconResourceBytes() {
+ return ResourceBundle::GetSharedInstance().
+ // TODO(garykac): Have custom remoting icon created.
+ LoadDataResourceBytes(IDR_PLUGIN);
+}
+
+// static
+void RemotingUI::RegisterUserPrefs(PrefService* prefs) {
+ // TODO(garykac): Add remoting prefs (if needed).
+}
diff --git a/chrome/browser/ui/webui/remoting_ui.h b/chrome/browser/ui/webui/remoting_ui.h
new file mode 100644
index 0000000..d5c43d9
--- /dev/null
+++ b/chrome/browser/ui/webui/remoting_ui.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_REMOTING_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_REMOTING_UI_H_
+#pragma once
+
+#include "content/browser/webui/web_ui.h"
+
+class PrefService;
+class RefCountedMemory;
+
+class RemotingUI : public WebUI {
+ public:
+ explicit RemotingUI(TabContents* contents);
+
+ static RefCountedMemory* GetFaviconResourceBytes();
+ static void RegisterUserPrefs(PrefService* prefs);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RemotingUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_REMOTING_UI_H_
diff --git a/chrome/browser/ui/webui/slideshow_ui.cc b/chrome/browser/ui/webui/slideshow_ui.cc
new file mode 100644
index 0000000..b8080ea
--- /dev/null
+++ b/chrome/browser/ui/webui/slideshow_ui.cc
@@ -0,0 +1,284 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/slideshow_ui.h"
+
+#include "base/callback.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/singleton.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/threading/thread.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "base/weak_ptr.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/webui/favicon_source.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "net/base/directory_lister.h"
+#include "net/base/escape.h"
+#include "ui/base/resource/resource_bundle.h"
+
+static const char kPropertyPath[] = "path";
+static const char kPropertyTitle[] = "title";
+static const char kPropertyOffset[] = "currentOffset";
+static const char kPropertyDirectory[] = "isDirectory";
+
+class SlideshowUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ SlideshowUIHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ ~SlideshowUIHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(SlideshowUIHTMLSource);
+};
+
+// The handler for Javascript messages related to the "slideshow" view.
+class SlideshowHandler : public net::DirectoryLister::DirectoryListerDelegate,
+ public WebUIMessageHandler,
+ public base::SupportsWeakPtr<SlideshowHandler> {
+ public:
+ SlideshowHandler();
+ virtual ~SlideshowHandler();
+
+ // Init work after Attach.
+ void Init();
+
+ // DirectoryLister::DirectoryListerDelegate methods:
+ virtual void OnListFile(
+ const net::DirectoryLister::DirectoryListerData& data);
+ virtual void OnListDone(int error);
+
+ // WebUIMessageHandler implementation.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+ virtual void RegisterMessages();
+
+ void GetChildrenForPath(const FilePath& path, bool is_refresh);
+
+ // Callback for the "getChildren" message.
+ void HandleGetChildren(const ListValue* args);
+
+ void HandleRefreshDirectory(const ListValue* args);
+
+ private:
+ bool PathIsImageFile(const char* filename);
+
+ scoped_ptr<ListValue> filelist_value_;
+ FilePath currentpath_;
+ FilePath originalpath_;
+ Profile* profile_;
+ int counter_;
+ int currentOffset_;
+ scoped_refptr<net::DirectoryLister> lister_;
+ bool is_refresh_;
+
+ DISALLOW_COPY_AND_ASSIGN(SlideshowHandler);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// SlideshowHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+SlideshowUIHTMLSource::SlideshowUIHTMLSource()
+ : DataSource(chrome::kChromeUISlideshowHost, MessageLoop::current()) {
+}
+
+void SlideshowUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ // TODO(dhg): Add stirings to localized strings, also add more strings
+ // that are currently hardcoded.
+ SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece slideshow_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_SLIDESHOW_HTML));
+ const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
+ slideshow_html, &localized_strings);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// SlideshowHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+SlideshowHandler::SlideshowHandler()
+ : profile_(NULL),
+ is_refresh_(false) {
+ lister_ = NULL;
+}
+
+SlideshowHandler::~SlideshowHandler() {
+ if (lister_.get()) {
+ lister_->Cancel();
+ lister_->set_delegate(NULL);
+ }
+}
+
+WebUIMessageHandler* SlideshowHandler::Attach(WebUI* web_ui) {
+ profile_ = web_ui->GetProfile();
+ // Create our favicon data source.
+ profile_->GetChromeURLDataManager()->AddDataSource(
+ new FavIconSource(profile_));
+ return WebUIMessageHandler::Attach(web_ui);
+}
+
+void SlideshowHandler::Init() {
+}
+
+void SlideshowHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("getChildren",
+ NewCallback(this, &SlideshowHandler::HandleGetChildren));
+ web_ui_->RegisterMessageCallback("refreshDirectory",
+ NewCallback(this, &SlideshowHandler::HandleRefreshDirectory));
+}
+
+void SlideshowHandler::HandleRefreshDirectory(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ GetChildrenForPath(FilePath(path), true);
+#endif
+}
+
+void SlideshowHandler::GetChildrenForPath(const FilePath& path,
+ bool is_refresh) {
+ filelist_value_.reset(new ListValue());
+ currentpath_ = path;
+
+ if (lister_.get()) {
+ lister_->Cancel();
+ lister_->set_delegate(NULL);
+ lister_ = NULL;
+ }
+
+ is_refresh_ = is_refresh;
+ if (file_util::EnsureEndsWithSeparator(&currentpath_) &&
+ currentpath_.IsAbsolute()) {
+ lister_ = new net::DirectoryLister(currentpath_, this);
+ } else {
+ originalpath_ = currentpath_;
+ currentpath_ = currentpath_.DirName();
+ lister_ = new net::DirectoryLister(currentpath_, this);
+ }
+ counter_ = 0;
+ currentOffset_ = -1;
+ lister_->Start();
+}
+
+void SlideshowHandler::HandleGetChildren(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ filelist_value_.reset(new ListValue());
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ GetChildrenForPath(FilePath(path), false);
+#endif
+}
+
+bool SlideshowHandler::PathIsImageFile(const char* filename) {
+#if defined(OS_CHROMEOS)
+ FilePath file = FilePath(filename);
+ std::string ext = file.Extension();
+ ext = StringToLowerASCII(ext);
+ if (ext == ".jpg" ||
+ ext == ".jpeg" ||
+ ext == ".png" ||
+ ext == ".gif") {
+ return true;
+ } else {
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
+void SlideshowHandler::OnListFile(
+ const net::DirectoryLister::DirectoryListerData& data) {
+#if defined(OS_CHROMEOS)
+ if (data.info.filename[0] == '.') {
+ return;
+ }
+ if (!PathIsImageFile(data.info.filename.c_str())) {
+ return;
+ }
+
+ DictionaryValue* file_value = new DictionaryValue();
+
+ file_value->SetString(kPropertyTitle, data.info.filename);
+ file_value->SetString(kPropertyPath,
+ currentpath_.Append(data.info.filename).value());
+ file_value->SetBoolean(kPropertyDirectory, S_ISDIR(data.info.stat.st_mode));
+ filelist_value_->Append(file_value);
+ std::string val;
+ file_value->GetString(kPropertyTitle, &val);
+ if (val == originalpath_.BaseName().value()) {
+ currentOffset_ = counter_;
+ }
+ counter_++;
+#endif
+}
+
+void SlideshowHandler::OnListDone(int error) {
+ DictionaryValue info_value;
+ counter_ = 0;
+ if (!(file_util::EnsureEndsWithSeparator(&originalpath_) &&
+ originalpath_.IsAbsolute()) &&
+ currentOffset_ != -1) {
+ info_value.SetInteger(kPropertyOffset, currentOffset_);
+ }
+ if (is_refresh_) {
+ info_value.SetString("functionCall", "refresh");
+ } else {
+ info_value.SetString("functionCall", "getChildren");
+ }
+ info_value.SetString(kPropertyPath, currentpath_.value());
+ web_ui_->CallJavascriptFunction(L"browseFileResult",
+ info_value, *(filelist_value_.get()));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// SlideshowUI
+//
+////////////////////////////////////////////////////////////////////////////////
+
+SlideshowUI::SlideshowUI(TabContents* contents) : WebUI(contents) {
+ SlideshowHandler* handler = new SlideshowHandler();
+ AddMessageHandler((handler)->Attach(this));
+ handler->Init();
+ SlideshowUIHTMLSource* html_source = new SlideshowUIHTMLSource();
+
+ // Set up the chrome://slideshow/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
diff --git a/chrome/browser/ui/webui/slideshow_ui.h b/chrome/browser/ui/webui/slideshow_ui.h
new file mode 100644
index 0000000..fd7413a
--- /dev/null
+++ b/chrome/browser/ui/webui/slideshow_ui.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SLIDESHOW_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_SLIDESHOW_UI_H_
+#pragma once
+
+#include "content/browser/webui/web_ui.h"
+
+class SlideshowUI : public WebUI {
+ public:
+ explicit SlideshowUI(TabContents* contents);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SlideshowUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_SLIDESHOW_UI_H_
diff --git a/chrome/browser/ui/webui/sync_internals_ui.cc b/chrome/browser/ui/webui/sync_internals_ui.cc
new file mode 100644
index 0000000..5edfbcc
--- /dev/null
+++ b/chrome/browser/ui/webui/sync_internals_ui.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/sync_internals_ui.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/ref_counted.h"
+#include "base/task.h"
+#include "base/tracked_objects.h"
+#include "base/values.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/js_arg_list.h"
+#include "chrome/browser/sync/js_frontend.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/sync_ui_util.h"
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "chrome/browser/webui/sync_internals_html_source.h"
+#include "chrome/common/render_messages_params.h"
+
+SyncInternalsUI::SyncInternalsUI(TabContents* contents)
+ : WebUI(contents) {
+ browser_sync::JsFrontend* backend = GetJsFrontend();
+ if (backend) {
+ backend->AddHandler(this);
+ }
+ // If this PostTask() call fails, it's most likely because this is
+ // being run from a unit test. The created objects will be cleaned
+ // up, anyway.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(
+ new SyncInternalsHTMLSource());
+}
+
+SyncInternalsUI::~SyncInternalsUI() {
+ browser_sync::JsFrontend* backend = GetJsFrontend();
+ if (backend) {
+ backend->RemoveHandler(this);
+ }
+}
+
+void SyncInternalsUI::ProcessWebUIMessage(
+ const ViewHostMsg_DomMessage_Params& params) {
+ const std::string& name = params.name;
+ browser_sync::JsArgList args(params.arguments);
+ VLOG(1) << "Received message: " << name << " with args "
+ << args.ToString();
+ // We handle this case directly because it needs to work even if
+ // the sync service doesn't exist.
+ if (name == "getAboutInfo") {
+ ListValue args;
+ DictionaryValue* about_info = new DictionaryValue();
+ args.Append(about_info);
+ ProfileSyncService* service = GetProfile()->GetProfileSyncService();
+ sync_ui_util::ConstructAboutInformation(service, about_info);
+ HandleJsEvent("onGetAboutInfoFinished",
+ browser_sync::JsArgList(args));
+ } else {
+ browser_sync::JsFrontend* backend = GetJsFrontend();
+ if (backend) {
+ backend->ProcessMessage(name, args, this);
+ } else {
+ LOG(WARNING) << "No sync service; dropping message " << name
+ << " with args " << args.ToString();
+ }
+ }
+}
+
+void SyncInternalsUI::HandleJsEvent(const std::string& name,
+ const browser_sync::JsArgList& args) {
+ VLOG(1) << "Handling event: " << name << " with args " << args.ToString();
+ std::vector<const Value*> arg_list(args.Get().begin(), args.Get().end());
+ CallJavascriptFunction(UTF8ToWide(name), arg_list);
+}
+
+browser_sync::JsFrontend* SyncInternalsUI::GetJsFrontend() {
+ // If this returns NULL that means that sync is disabled for
+ // whatever reason.
+ ProfileSyncService* sync_service = GetProfile()->GetProfileSyncService();
+ return sync_service ? sync_service->GetJsFrontend() : NULL;
+}
diff --git a/chrome/browser/ui/webui/sync_internals_ui.h b/chrome/browser/ui/webui/sync_internals_ui.h
new file mode 100644
index 0000000..0afdca4
--- /dev/null
+++ b/chrome/browser/ui/webui/sync_internals_ui.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_UI_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/browser/sync/js_event_handler.h"
+#include "content/browser/webui/web_ui.h"
+
+namespace browser_sync {
+class JsFrontend;
+} // namespace browser_sync
+
+// The implementation for the chrome://sync-internals page.
+class SyncInternalsUI : public WebUI, public browser_sync::JsEventHandler {
+ public:
+ explicit SyncInternalsUI(TabContents* contents);
+ virtual ~SyncInternalsUI();
+
+ // WebUI implementation.
+ //
+ // The following messages are processed:
+ //
+ // getAboutInfo():
+ // Immediately fires a onGetAboutInfoFinished() event with a
+ // dictionary of sync-related stats and info.
+ //
+ // All other messages are routed to the sync service if it exists,
+ // and dropped otherwise.
+ //
+ // TODO(akalin): Add a simple isSyncEnabled() message and make
+ // getAboutInfo() be handled by the sync service.
+ virtual void ProcessWebUIMessage(
+ const ViewHostMsg_DomMessage_Params& params);
+
+ // browser_sync::JsEventHandler implementation.
+ virtual void HandleJsEvent(const std::string& name,
+ const browser_sync::JsArgList& args);
+
+ private:
+ // Returns the sync service's JsFrontend object, or NULL if the sync
+ // service does not exist.
+ browser_sync::JsFrontend* GetJsFrontend();
+
+ DISALLOW_COPY_AND_ASSIGN(SyncInternalsUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_UI_H_
diff --git a/chrome/browser/ui/webui/sync_internals_ui_unittest.cc b/chrome/browser/ui/webui/sync_internals_ui_unittest.cc
new file mode 100644
index 0000000..379a704
--- /dev/null
+++ b/chrome/browser/ui/webui/sync_internals_ui_unittest.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/sync_internals_ui.h"
+
+#include <cstddef>
+#include <string>
+
+#include "base/message_loop.h"
+#include "base/values.h"
+#include "chrome/browser/sync/js_arg_list.h"
+#include "chrome/browser/sync/js_test_util.h"
+#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
+#include "chrome/common/render_messages_params.h"
+#include "chrome/test/profile_mock.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/renderer_host/test_render_view_host.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using browser_sync::HasArgsAsList;
+using browser_sync::JsArgList;
+using testing::NiceMock;
+using testing::Return;
+using testing::StrictMock;
+
+// Subclass of SyncInternalsUI to mock out ExecuteJavascript.
+class TestSyncInternalsUI : public SyncInternalsUI {
+ public:
+ explicit TestSyncInternalsUI(TabContents* contents)
+ : SyncInternalsUI(contents) {}
+ virtual ~TestSyncInternalsUI() {}
+
+ MOCK_METHOD1(ExecuteJavascript, void(const std::wstring&));
+};
+
+class SyncInternalsUITest : public RenderViewHostTestHarness {
+ protected:
+ // We allocate memory for |sync_internals_ui_| but we don't
+ // construct it. This is because we want to set mock expectations
+ // with its address before we construct it, and its constructor
+ // calls into our mocks.
+ SyncInternalsUITest()
+ // The message loop is provided by RenderViewHostTestHarness.
+ : ui_thread_(BrowserThread::UI, MessageLoopForUI::current()),
+ test_sync_internals_ui_buf_(NULL),
+ test_sync_internals_ui_constructor_called_(false) {}
+
+ virtual void SetUp() {
+ test_sync_internals_ui_buf_ = operator new(sizeof(TestSyncInternalsUI));
+ test_sync_internals_ui_constructor_called_ = false;
+ profile_.reset(new NiceMock<ProfileMock>());
+ RenderViewHostTestHarness::SetUp();
+ }
+
+ virtual void TearDown() {
+ if (test_sync_internals_ui_constructor_called_) {
+ GetTestSyncInternalsUI()->~TestSyncInternalsUI();
+ }
+ operator delete(test_sync_internals_ui_buf_);
+ RenderViewHostTestHarness::TearDown();
+ }
+
+ NiceMock<ProfileMock>* GetProfileMock() {
+ return static_cast<NiceMock<ProfileMock>*>(profile());
+ }
+
+ // Set up boilerplate expectations for calls done during
+ // SyncInternalUI's construction/destruction.
+ void ExpectSetupTeardownCalls() {
+ EXPECT_CALL(*GetProfileMock(), GetProfileSyncService())
+ .WillRepeatedly(Return(&profile_sync_service_mock_));
+
+ EXPECT_CALL(profile_sync_service_mock_, GetJsFrontend())
+ .WillRepeatedly(Return(&mock_js_backend_));
+
+ // Called by sync_ui_util::ConstructAboutInformation().
+ EXPECT_CALL(profile_sync_service_mock_, HasSyncSetupCompleted())
+ .WillRepeatedly(Return(false));
+
+ // Called by SyncInternalsUI's constructor.
+ EXPECT_CALL(mock_js_backend_,
+ AddHandler(GetTestSyncInternalsUIAddress()));
+
+ // Called by SyncInternalUI's destructor.
+ EXPECT_CALL(mock_js_backend_,
+ RemoveHandler(GetTestSyncInternalsUIAddress()));
+ }
+
+ // Like ExpectSetupTeardownCalls() but with a NULL
+ // ProfileSyncService.
+ void ExpectSetupTeardownCallsNullService() {
+ EXPECT_CALL(*GetProfileMock(), GetProfileSyncService())
+ .WillRepeatedly(Return(static_cast<ProfileSyncService*>(NULL)));
+ }
+
+ void ConstructTestSyncInternalsUI() {
+ if (test_sync_internals_ui_constructor_called_) {
+ ADD_FAILURE() << "ConstructTestSyncInternalsUI() should be called "
+ << "at most once per test";
+ return;
+ }
+ new(test_sync_internals_ui_buf_) TestSyncInternalsUI(contents());
+ test_sync_internals_ui_constructor_called_ = true;
+ }
+
+ TestSyncInternalsUI* GetTestSyncInternalsUI() {
+ if (!test_sync_internals_ui_constructor_called_) {
+ ADD_FAILURE() << "ConstructTestSyncInternalsUI() should be called "
+ << "before GetTestSyncInternalsUI()";
+ return NULL;
+ }
+ return GetTestSyncInternalsUIAddress();
+ }
+
+ // Used for passing into EXPECT_CALL().
+ TestSyncInternalsUI* GetTestSyncInternalsUIAddress() {
+ EXPECT_TRUE(test_sync_internals_ui_buf_);
+ return static_cast<TestSyncInternalsUI*>(test_sync_internals_ui_buf_);
+ }
+
+ StrictMock<ProfileSyncServiceMock> profile_sync_service_mock_;
+ StrictMock<browser_sync::MockJsFrontend> mock_js_backend_;
+
+ private:
+ // Needed by |contents()|.
+ BrowserThread ui_thread_;
+ void* test_sync_internals_ui_buf_;
+ bool test_sync_internals_ui_constructor_called_;
+};
+
+TEST_F(SyncInternalsUITest, HandleJsEvent) {
+ ExpectSetupTeardownCalls();
+
+ ConstructTestSyncInternalsUI();
+
+ EXPECT_CALL(*GetTestSyncInternalsUI(),
+ ExecuteJavascript(std::wstring(L"testMessage(5,true);")));
+
+ ListValue args;
+ args.Append(Value::CreateIntegerValue(5));
+ args.Append(Value::CreateBooleanValue(true));
+ GetTestSyncInternalsUI()->HandleJsEvent("testMessage", JsArgList(args));
+}
+
+TEST_F(SyncInternalsUITest, HandleJsEventNullService) {
+ ExpectSetupTeardownCallsNullService();
+
+ ConstructTestSyncInternalsUI();
+
+ EXPECT_CALL(*GetTestSyncInternalsUI(),
+ ExecuteJavascript(std::wstring(L"testMessage(5,true);")));
+
+ ListValue args;
+ args.Append(Value::CreateIntegerValue(5));
+ args.Append(Value::CreateBooleanValue(true));
+ GetTestSyncInternalsUI()->HandleJsEvent("testMessage", JsArgList(args));
+}
+
+TEST_F(SyncInternalsUITest, ProcessWebUIMessageBasic) {
+ ExpectSetupTeardownCalls();
+
+ ViewHostMsg_DomMessage_Params params;
+ params.name = "testName";
+ params.arguments.Append(Value::CreateIntegerValue(10));
+
+ EXPECT_CALL(mock_js_backend_,
+ ProcessMessage(params.name, HasArgsAsList(params.arguments),
+ GetTestSyncInternalsUIAddress()));
+
+ ConstructTestSyncInternalsUI();
+
+ GetTestSyncInternalsUI()->ProcessWebUIMessage(params);
+}
+
+TEST_F(SyncInternalsUITest, ProcessWebUIMessageBasicNullService) {
+ ExpectSetupTeardownCallsNullService();
+
+ ConstructTestSyncInternalsUI();
+
+ ViewHostMsg_DomMessage_Params params;
+ params.name = "testName";
+ params.arguments.Append(Value::CreateIntegerValue(5));
+
+ // Should drop the message.
+ GetTestSyncInternalsUI()->ProcessWebUIMessage(params);
+}
+
+namespace {
+const wchar_t kAboutInfoCall[] =
+ L"onGetAboutInfoFinished({\"summary\":\"SYNC DISABLED\"});";
+} // namespace
+
+TEST_F(SyncInternalsUITest, ProcessWebUIMessageGetAboutInfo) {
+ ExpectSetupTeardownCalls();
+
+ ViewHostMsg_DomMessage_Params params;
+ params.name = "getAboutInfo";
+
+ ConstructTestSyncInternalsUI();
+
+ EXPECT_CALL(*GetTestSyncInternalsUI(),
+ ExecuteJavascript(std::wstring(kAboutInfoCall)));
+
+ GetTestSyncInternalsUI()->ProcessWebUIMessage(params);
+}
+
+TEST_F(SyncInternalsUITest, ProcessWebUIMessageGetAboutInfoNullService) {
+ ExpectSetupTeardownCallsNullService();
+
+ ViewHostMsg_DomMessage_Params params;
+ params.name = "getAboutInfo";
+
+ ConstructTestSyncInternalsUI();
+
+ EXPECT_CALL(*GetTestSyncInternalsUI(),
+ ExecuteJavascript(std::wstring(kAboutInfoCall)));
+
+ GetTestSyncInternalsUI()->ProcessWebUIMessage(params);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/webui/textfields_ui.cc b/chrome/browser/ui/webui/textfields_ui.cc
new file mode 100644
index 0000000..73217e0
--- /dev/null
+++ b/chrome/browser/ui/webui/textfields_ui.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/textfields_ui.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/singleton.h"
+#include "base/string_piece.h"
+#include "base/values.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+/**
+ * TextfieldsUIHTMLSource implementation.
+ */
+TextfieldsUIHTMLSource::TextfieldsUIHTMLSource()
+ : DataSource(chrome::kChromeUITextfieldsHost, MessageLoop::current()) {
+}
+
+void TextfieldsUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ const std::string full_html = ResourceBundle::GetSharedInstance()
+ .GetRawDataResource(IDR_TEXTFIELDS_HTML).as_string();
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+std::string TextfieldsUIHTMLSource::GetMimeType(
+ const std::string& /* path */) const {
+ return "text/html";
+}
+
+TextfieldsUIHTMLSource::~TextfieldsUIHTMLSource() {}
+
+/**
+ * TextfieldsDOMHandler implementation.
+ */
+TextfieldsDOMHandler::TextfieldsDOMHandler() : WebUIMessageHandler() {}
+
+void TextfieldsDOMHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("textfieldValue",
+ NewCallback(this, &TextfieldsDOMHandler::HandleTextfieldValue));
+}
+
+void TextfieldsDOMHandler::HandleTextfieldValue(const ListValue* args) {
+ static_cast<TextfieldsUI*>(web_ui_)->set_text(ExtractStringValue(args));
+}
+
+/**
+ * TextfieldsUI implementation.
+ */
+TextfieldsUI::TextfieldsUI(TabContents* contents) : WebUI(contents) {
+ TextfieldsDOMHandler* handler = new TextfieldsDOMHandler();
+ AddMessageHandler(handler);
+ handler->Attach(this);
+
+ TextfieldsUIHTMLSource* html_source = new TextfieldsUIHTMLSource();
+
+ // Set up the chrome://textfields/ source.
+ contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
+}
diff --git a/chrome/browser/ui/webui/textfields_ui.h b/chrome/browser/ui/webui/textfields_ui.h
new file mode 100644
index 0000000..1b62982
--- /dev/null
+++ b/chrome/browser/ui/webui/textfields_ui.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_TEXTFIELDS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_TEXTFIELDS_UI_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/webui/chrome_url_data_manager.h"
+#include "content/browser/webui/web_ui.h"
+
+class RefCountedMemory;
+
+/**
+ * ChromeURLDataManager::DataSource implementation that asynchronously answers
+ * requests for chrome://textfields URL. On receiving a request, this object
+ * reads the html from the local resource textfields.html and sends back the
+ * response.
+ */
+class TextfieldsUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ TextfieldsUIHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string& path) const;
+
+ private:
+ virtual ~TextfieldsUIHTMLSource();
+
+ DISALLOW_COPY_AND_ASSIGN(TextfieldsUIHTMLSource);
+};
+
+/**
+ * Handler for JavaScript calls from the DOM.
+ */
+class TextfieldsDOMHandler : public WebUIMessageHandler {
+ public:
+ TextfieldsDOMHandler();
+
+ // Handles the "textfieldValue" call from the JavaScript. This call
+ // synchonizes the value inside the JavaScript textfield with the copy in the
+ // DOM object.
+ virtual void HandleTextfieldValue(const ListValue* args);
+
+ protected:
+ virtual void RegisterMessages();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextfieldsDOMHandler);
+};
+
+class TextfieldsUI : public WebUI {
+ public:
+ explicit TextfieldsUI(TabContents* contents);
+
+ const std::wstring& text() const { return text_; }
+ void set_text(const std::wstring& text) { text_ = text; }
+
+ private:
+ std::wstring text_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextfieldsUI);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_TEXTFIELDS_UI_H_