Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(184)

Side by Side Diff: chrome/browser/ui/browser.cc

Issue 836933005: Refactor fullscreen_controller. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix build break Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/browser.h" 5 #include "chrome/browser/ui/browser.h"
6 6
7 #if defined(OS_WIN) 7 #if defined(OS_WIN)
8 #include <windows.h> 8 #include <windows.h>
9 #include <shellapi.h> 9 #include <shellapi.h>
10 #endif // defined(OS_WIN) 10 #endif // defined(OS_WIN)
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 #include "chrome/browser/ui/browser_navigator.h" 98 #include "chrome/browser/ui/browser_navigator.h"
99 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h" 99 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
100 #include "chrome/browser/ui/browser_tab_strip_model_delegate.h" 100 #include "chrome/browser/ui/browser_tab_strip_model_delegate.h"
101 #include "chrome/browser/ui/browser_tabstrip.h" 101 #include "chrome/browser/ui/browser_tabstrip.h"
102 #include "chrome/browser/ui/browser_toolbar_model_delegate.h" 102 #include "chrome/browser/ui/browser_toolbar_model_delegate.h"
103 #include "chrome/browser/ui/browser_ui_prefs.h" 103 #include "chrome/browser/ui/browser_ui_prefs.h"
104 #include "chrome/browser/ui/browser_window.h" 104 #include "chrome/browser/ui/browser_window.h"
105 #include "chrome/browser/ui/chrome_pages.h" 105 #include "chrome/browser/ui/chrome_pages.h"
106 #include "chrome/browser/ui/chrome_select_file_policy.h" 106 #include "chrome/browser/ui/chrome_select_file_policy.h"
107 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" 107 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
108 #include "chrome/browser/ui/exclusive_access/mouse_lock_controller.h"
108 #include "chrome/browser/ui/fast_unload_controller.h" 109 #include "chrome/browser/ui/fast_unload_controller.h"
109 #include "chrome/browser/ui/find_bar/find_bar.h" 110 #include "chrome/browser/ui/find_bar/find_bar.h"
110 #include "chrome/browser/ui/find_bar/find_bar_controller.h" 111 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
111 #include "chrome/browser/ui/find_bar/find_tab_helper.h" 112 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
112 #include "chrome/browser/ui/global_error/global_error.h" 113 #include "chrome/browser/ui/global_error/global_error.h"
113 #include "chrome/browser/ui/global_error/global_error_service.h" 114 #include "chrome/browser/ui/global_error/global_error_service.h"
114 #include "chrome/browser/ui/global_error/global_error_service_factory.h" 115 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
115 #include "chrome/browser/ui/location_bar/location_bar.h" 116 #include "chrome/browser/ui/location_bar/location_bar.h"
116 #include "chrome/browser/ui/media_utils.h" 117 #include "chrome/browser/ui/media_utils.h"
117 #include "chrome/browser/ui/search/search_delegate.h" 118 #include "chrome/browser/ui/search/search_delegate.h"
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 439
439 // TODO(beng): move to ChromeBrowserMain: 440 // TODO(beng): move to ChromeBrowserMain:
440 if (first_run::ShouldDoPersonalDataManagerFirstRun()) { 441 if (first_run::ShouldDoPersonalDataManagerFirstRun()) {
441 #if defined(OS_WIN) 442 #if defined(OS_WIN)
442 // Notify PDM that this is a first run. 443 // Notify PDM that this is a first run.
443 ImportAutofillDataWin( 444 ImportAutofillDataWin(
444 autofill::PersonalDataManagerFactory::GetForProfile(profile_)); 445 autofill::PersonalDataManagerFactory::GetForProfile(profile_));
445 #endif // defined(OS_WIN) 446 #endif // defined(OS_WIN)
446 } 447 }
447 448
448 fullscreen_controller_.reset(new FullscreenController(this)); 449 exclusive_access_manager_.reset(new ExclusiveAccessManager(this));
449 450
450 // Must be initialized after window_. 451 // Must be initialized after window_.
451 // Also: surprise! a modal dialog host is not necessary to host modal dialogs 452 // Also: surprise! a modal dialog host is not necessary to host modal dialogs
452 // without a modal dialog host, so that value may be null. 453 // without a modal dialog host, so that value may be null.
453 popup_manager_.reset(new web_modal::PopupManager( 454 popup_manager_.reset(new web_modal::PopupManager(
454 GetWebContentsModalDialogHost())); 455 GetWebContentsModalDialogHost()));
455 } 456 }
456 457
457 Browser::~Browser() { 458 Browser::~Browser() {
458 // Stop observing notifications before continuing with destruction. Profile 459 // Stop observing notifications before continuing with destruction. Profile
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
778 } 779 }
779 780
780 // Those are the only conditions under which we will block shutdown. 781 // Those are the only conditions under which we will block shutdown.
781 return DOWNLOAD_CLOSE_OK; 782 return DOWNLOAD_CLOSE_OK;
782 } 783 }
783 784
784 //////////////////////////////////////////////////////////////////////////////// 785 ////////////////////////////////////////////////////////////////////////////////
785 // Browser, Tab adding/showing functions: 786 // Browser, Tab adding/showing functions:
786 787
787 void Browser::WindowFullscreenStateChanged() { 788 void Browser::WindowFullscreenStateChanged() {
788 fullscreen_controller_->WindowFullscreenStateChanged(); 789 exclusive_access_manager_->GetFullscreenController()
790 ->WindowFullscreenStateChanged();
789 command_controller_->FullscreenStateChanged(); 791 command_controller_->FullscreenStateChanged();
790 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TOGGLE_FULLSCREEN); 792 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TOGGLE_FULLSCREEN);
791 } 793 }
792 794
793 /////////////////////////////////////////////////////////////////////////////// 795 ///////////////////////////////////////////////////////////////////////////////
794 // Browser, Assorted browser commands: 796 // Browser, Assorted browser commands:
795 797
796 void Browser::ToggleFullscreenModeWithExtension(const GURL& extension_url) { 798 void Browser::ToggleFullscreenModeWithExtension(const GURL& extension_url) {
797 fullscreen_controller_-> 799 exclusive_access_manager_->GetFullscreenController()
798 ToggleBrowserFullscreenModeWithExtension(extension_url); 800 ->ToggleBrowserFullscreenModeWithExtension(extension_url);
799 } 801 }
800 802
801 bool Browser::SupportsWindowFeature(WindowFeature feature) const { 803 bool Browser::SupportsWindowFeature(WindowFeature feature) const {
802 return SupportsWindowFeatureImpl(feature, true); 804 return SupportsWindowFeatureImpl(feature, true);
803 } 805 }
804 806
805 bool Browser::CanSupportWindowFeature(WindowFeature feature) const { 807 bool Browser::CanSupportWindowFeature(WindowFeature feature) const {
806 return SupportsWindowFeatureImpl(feature, false); 808 return SupportsWindowFeatureImpl(feature, false);
807 } 809 }
808 810
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
938 int new_active_index = tab_strip_model_->active_index(); 940 int new_active_index = tab_strip_model_->active_index();
939 if (index < new_active_index) 941 if (index < new_active_index)
940 session_service->SetSelectedTabInWindow(session_id(), 942 session_service->SetSelectedTabInWindow(session_id(),
941 new_active_index); 943 new_active_index);
942 } 944 }
943 } 945 }
944 946
945 void Browser::TabClosingAt(TabStripModel* tab_strip_model, 947 void Browser::TabClosingAt(TabStripModel* tab_strip_model,
946 WebContents* contents, 948 WebContents* contents,
947 int index) { 949 int index) {
948 fullscreen_controller_->OnTabClosing(contents); 950 exclusive_access_manager_->OnTabClosing(contents);
949 SessionService* session_service = 951 SessionService* session_service =
950 SessionServiceFactory::GetForProfile(profile_); 952 SessionServiceFactory::GetForProfile(profile_);
951 if (session_service) 953 if (session_service)
952 session_service->TabClosing(contents); 954 session_service->TabClosing(contents);
953 content::NotificationService::current()->Notify( 955 content::NotificationService::current()->Notify(
954 chrome::NOTIFICATION_TAB_CLOSING, 956 chrome::NOTIFICATION_TAB_CLOSING,
955 content::Source<NavigationController>(&contents->GetController()), 957 content::Source<NavigationController>(&contents->GetController()),
956 content::NotificationService::NoDetails()); 958 content::NotificationService::NoDetails());
957 959
958 if (popup_manager_) 960 if (popup_manager_)
(...skipping 15 matching lines...) Expand all
974 old_active_index - 1); 976 old_active_index - 1);
975 } 977 }
976 978
977 if (popup_manager_) 979 if (popup_manager_)
978 popup_manager_->UnregisterWith(contents); 980 popup_manager_->UnregisterWith(contents);
979 981
980 TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH); 982 TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH);
981 } 983 }
982 984
983 void Browser::TabDeactivated(WebContents* contents) { 985 void Browser::TabDeactivated(WebContents* contents) {
984 fullscreen_controller_->OnTabDeactivated(contents); 986 exclusive_access_manager_->OnTabDeactivated(contents);
985 search_delegate_->OnTabDeactivated(contents); 987 search_delegate_->OnTabDeactivated(contents);
986 SearchTabHelper::FromWebContents(contents)->OnTabDeactivated(); 988 SearchTabHelper::FromWebContents(contents)->OnTabDeactivated();
987 989
988 // Save what the user's currently typing, so it can be restored when we 990 // Save what the user's currently typing, so it can be restored when we
989 // switch back to this tab. 991 // switch back to this tab.
990 window_->GetLocationBar()->SaveStateToContents(contents); 992 window_->GetLocationBar()->SaveStateToContents(contents);
991 993
992 if (instant_controller_) 994 if (instant_controller_)
993 instant_controller_->TabDeactivated(contents); 995 instant_controller_->TabDeactivated(contents);
994 } 996 }
995 997
996 void Browser::ActiveTabChanged(WebContents* old_contents, 998 void Browser::ActiveTabChanged(WebContents* old_contents,
997 WebContents* new_contents, 999 WebContents* new_contents,
998 int index, 1000 int index,
999 int reason) { 1001 int reason) {
1000 content::RecordAction(UserMetricsAction("ActiveTabChanged")); 1002 content::RecordAction(UserMetricsAction("ActiveTabChanged"));
1001 1003
1002 // Update the bookmark state, since the BrowserWindow may query it during 1004 // Update the bookmark state, since the BrowserWindow may query it during
1003 // OnActiveTabChanged() below. 1005 // OnActiveTabChanged() below.
1004 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_SWITCH); 1006 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_SWITCH);
1005 1007
1006 // Let the BrowserWindow do its handling. On e.g. views this changes the 1008 // Let the BrowserWindow do its handling. On e.g. views this changes the
1007 // focused object, which should happen before we update the toolbar below, 1009 // focused object, which should happen before we update the toolbar below,
1008 // since the omnibox expects the correct element to already be focused when it 1010 // since the omnibox expects the correct element to already be focused when it
1009 // is updated. 1011 // is updated.
1010 window_->OnActiveTabChanged(old_contents, new_contents, index, reason); 1012 window_->OnActiveTabChanged(old_contents, new_contents, index, reason);
1011 1013
1012 fullscreen_controller_->OnTabDetachedFromView(old_contents); 1014 exclusive_access_manager_->OnTabDetachedFromView(old_contents);
1013 1015
1014 // Discarded tabs always get reloaded. 1016 // Discarded tabs always get reloaded.
1015 if (tab_strip_model_->IsTabDiscarded(index)) { 1017 if (tab_strip_model_->IsTabDiscarded(index)) {
1016 LOG(WARNING) << "Reloading discarded tab at " << index; 1018 LOG(WARNING) << "Reloading discarded tab at " << index;
1017 static int reload_count = 0; 1019 static int reload_count = 0;
1018 UMA_HISTOGRAM_CUSTOM_COUNTS( 1020 UMA_HISTOGRAM_CUSTOM_COUNTS(
1019 "Tabs.Discard.ReloadCount", ++reload_count, 1, 1000, 50); 1021 "Tabs.Discard.ReloadCount", ++reload_count, 1, 1000, 50);
1020 chrome::Reload(this, CURRENT_TAB); 1022 chrome::Reload(this, CURRENT_TAB);
1021 } 1023 }
1022 1024
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1074 DCHECK(from_index >= 0 && to_index >= 0); 1076 DCHECK(from_index >= 0 && to_index >= 0);
1075 // Notify the history service. 1077 // Notify the history service.
1076 SyncHistoryWithTabs(std::min(from_index, to_index)); 1078 SyncHistoryWithTabs(std::min(from_index, to_index));
1077 } 1079 }
1078 1080
1079 void Browser::TabReplacedAt(TabStripModel* tab_strip_model, 1081 void Browser::TabReplacedAt(TabStripModel* tab_strip_model,
1080 WebContents* old_contents, 1082 WebContents* old_contents,
1081 WebContents* new_contents, 1083 WebContents* new_contents,
1082 int index) { 1084 int index) {
1083 TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE); 1085 TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE);
1084 fullscreen_controller_->OnTabClosing(old_contents); 1086 exclusive_access_manager_->OnTabClosing(old_contents);
1085 SessionService* session_service = 1087 SessionService* session_service =
1086 SessionServiceFactory::GetForProfile(profile_); 1088 SessionServiceFactory::GetForProfile(profile_);
1087 if (session_service) 1089 if (session_service)
1088 session_service->TabClosing(old_contents); 1090 session_service->TabClosing(old_contents);
1089 TabInsertedAt(new_contents, 1091 TabInsertedAt(new_contents,
1090 index, 1092 index,
1091 (index == tab_strip_model_->active_index())); 1093 (index == tab_strip_model_->active_index()));
1092 1094
1093 int entry_count = new_contents->GetController().GetEntryCount(); 1095 int entry_count = new_contents->GetController().GetEntryCount();
1094 if (entry_count > 0) { 1096 if (entry_count > 0) {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1177 GURL committed_url(source->GetController().GetLastCommittedEntry()->GetURL()); 1179 GURL committed_url(source->GetController().GetLastCommittedEntry()->GetURL());
1178 return chrome::IsNTPURL(committed_url, profile); 1180 return chrome::IsNTPURL(committed_url, profile);
1179 } 1181 }
1180 1182
1181 bool Browser::PreHandleKeyboardEvent(content::WebContents* source, 1183 bool Browser::PreHandleKeyboardEvent(content::WebContents* source,
1182 const NativeWebKeyboardEvent& event, 1184 const NativeWebKeyboardEvent& event,
1183 bool* is_keyboard_shortcut) { 1185 bool* is_keyboard_shortcut) {
1184 // Escape exits tabbed fullscreen mode. 1186 // Escape exits tabbed fullscreen mode.
1185 // TODO(koz): Write a test for this http://crbug.com/100441. 1187 // TODO(koz): Write a test for this http://crbug.com/100441.
1186 if (event.windowsKeyCode == 27 && 1188 if (event.windowsKeyCode == 27 &&
1187 fullscreen_controller_->HandleUserPressedEscape()) { 1189 exclusive_access_manager_->HandleUserPressedEscape()) {
1188 return true; 1190 return true;
1189 } 1191 }
1190 return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut); 1192 return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut);
1191 } 1193 }
1192 1194
1193 void Browser::HandleKeyboardEvent(content::WebContents* source, 1195 void Browser::HandleKeyboardEvent(content::WebContents* source,
1194 const NativeWebKeyboardEvent& event) { 1196 const NativeWebKeyboardEvent& event) {
1195 DevToolsWindow* devtools_window = 1197 DevToolsWindow* devtools_window =
1196 DevToolsWindow::GetInstanceForInspectedWebContents(source); 1198 DevToolsWindow::GetInstanceForInspectedWebContents(source);
1197 bool handled = false; 1199 bool handled = false;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1255 // Disallow drag-and-drop navigation for Settings windows which do not support 1257 // Disallow drag-and-drop navigation for Settings windows which do not support
1256 // external navigation. 1258 // external navigation.
1257 if ((operations_allowed & blink::WebDragOperationLink) && 1259 if ((operations_allowed & blink::WebDragOperationLink) &&
1258 chrome::SettingsWindowManager::GetInstance()->IsSettingsBrowser(this)) { 1260 chrome::SettingsWindowManager::GetInstance()->IsSettingsBrowser(this)) {
1259 return false; 1261 return false;
1260 } 1262 }
1261 return true; 1263 return true;
1262 } 1264 }
1263 1265
1264 bool Browser::IsMouseLocked() const { 1266 bool Browser::IsMouseLocked() const {
1265 return fullscreen_controller_->IsMouseLocked(); 1267 return exclusive_access_manager_->GetMouseLockController()->IsMouseLocked();
1266 } 1268 }
1267 1269
1268 void Browser::OnWindowDidShow() { 1270 void Browser::OnWindowDidShow() {
1269 if (window_has_shown_) 1271 if (window_has_shown_)
1270 return; 1272 return;
1271 window_has_shown_ = true; 1273 window_has_shown_ = true;
1272 1274
1273 // CurrentProcessInfo::CreationTime() is missing on some platforms. 1275 // CurrentProcessInfo::CreationTime() is missing on some platforms.
1274 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX) 1276 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX)
1275 // Measure the latency from startup till the first browser window becomes 1277 // Measure the latency from startup till the first browser window becomes
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after
1659 const base::FilePath& path) { 1661 const base::FilePath& path) {
1660 FileSelectHelper::EnumerateDirectory(web_contents, request_id, path); 1662 FileSelectHelper::EnumerateDirectory(web_contents, request_id, path);
1661 } 1663 }
1662 1664
1663 bool Browser::EmbedsFullscreenWidget() const { 1665 bool Browser::EmbedsFullscreenWidget() const {
1664 return true; 1666 return true;
1665 } 1667 }
1666 1668
1667 void Browser::ToggleFullscreenModeForTab(WebContents* web_contents, 1669 void Browser::ToggleFullscreenModeForTab(WebContents* web_contents,
1668 bool enter_fullscreen) { 1670 bool enter_fullscreen) {
1669 fullscreen_controller_->ToggleFullscreenModeForTab(web_contents, 1671 exclusive_access_manager_->GetFullscreenController()
1670 enter_fullscreen); 1672 ->ToggleFullscreenModeForTab(web_contents, enter_fullscreen);
1671 } 1673 }
1672 1674
1673 bool Browser::IsFullscreenForTabOrPending( 1675 bool Browser::IsFullscreenForTabOrPending(
1674 const WebContents* web_contents) const { 1676 const WebContents* web_contents) const {
1675 return fullscreen_controller_->IsFullscreenForTabOrPending(web_contents); 1677 return exclusive_access_manager_->GetFullscreenController()
1678 ->IsFullscreenForTabOrPending(web_contents);
1676 } 1679 }
1677 1680
1678 void Browser::RegisterProtocolHandler(WebContents* web_contents, 1681 void Browser::RegisterProtocolHandler(WebContents* web_contents,
1679 const std::string& protocol, 1682 const std::string& protocol,
1680 const GURL& url, 1683 const GURL& url,
1681 bool user_gesture) { 1684 bool user_gesture) {
1682 content::BrowserContext* context = web_contents->GetBrowserContext(); 1685 content::BrowserContext* context = web_contents->GetBrowserContext();
1683 if (context->IsOffTheRecord()) 1686 if (context->IsOffTheRecord())
1684 return; 1687 return;
1685 1688
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1761 find_tab_helper->HandleFindReply(request_id, 1764 find_tab_helper->HandleFindReply(request_id,
1762 number_of_matches, 1765 number_of_matches,
1763 selection_rect, 1766 selection_rect,
1764 active_match_ordinal, 1767 active_match_ordinal,
1765 final_update); 1768 final_update);
1766 } 1769 }
1767 1770
1768 void Browser::RequestToLockMouse(WebContents* web_contents, 1771 void Browser::RequestToLockMouse(WebContents* web_contents,
1769 bool user_gesture, 1772 bool user_gesture,
1770 bool last_unlocked_by_target) { 1773 bool last_unlocked_by_target) {
1771 fullscreen_controller_->RequestToLockMouse(web_contents, 1774 exclusive_access_manager_->GetMouseLockController()->RequestToLockMouse(
1772 user_gesture, 1775 web_contents, user_gesture, last_unlocked_by_target);
1773 last_unlocked_by_target);
1774 } 1776 }
1775 1777
1776 void Browser::LostMouseLock() { 1778 void Browser::LostMouseLock() {
1777 fullscreen_controller_->LostMouseLock(); 1779 exclusive_access_manager_->GetMouseLockController()->LostMouseLock();
1778 } 1780 }
1779 1781
1780 void Browser::RequestMediaAccessPermission( 1782 void Browser::RequestMediaAccessPermission(
1781 content::WebContents* web_contents, 1783 content::WebContents* web_contents,
1782 const content::MediaStreamRequest& request, 1784 const content::MediaStreamRequest& request,
1783 const content::MediaResponseCallback& callback) { 1785 const content::MediaResponseCallback& callback) {
1784 ::RequestMediaAccessPermission(web_contents, profile_, request, callback); 1786 ::RequestMediaAccessPermission(web_contents, profile_, request, callback);
1785 } 1787 }
1786 1788
1787 bool Browser::CheckMediaAccessPermission(content::WebContents* web_contents, 1789 bool Browser::CheckMediaAccessPermission(content::WebContents* web_contents,
(...skipping 722 matching lines...) Expand 10 before | Expand all | Expand 10 after
2510 if (contents && !allow_js_access) { 2512 if (contents && !allow_js_access) {
2511 contents->web_contents()->GetController().LoadURL( 2513 contents->web_contents()->GetController().LoadURL(
2512 target_url, 2514 target_url,
2513 content::Referrer(), 2515 content::Referrer(),
2514 ui::PAGE_TRANSITION_LINK, 2516 ui::PAGE_TRANSITION_LINK,
2515 std::string()); // No extra headers. 2517 std::string()); // No extra headers.
2516 } 2518 }
2517 2519
2518 return contents != NULL; 2520 return contents != NULL;
2519 } 2521 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698