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

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

Issue 9479008: Re-factor location bar/toolbar code to get rid of the browser dependency. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ut fix Created 8 years, 9 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 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/content_settings/content_setting_bubble_model.h" 5 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
6 6
7 #include "base/utf_string_conversions.h" 7 #include "base/utf_string_conversions.h"
8 #include "chrome/browser/content_settings/content_settings_utils.h" 8 #include "chrome/browser/content_settings/content_settings_utils.h"
9 #include "chrome/browser/content_settings/cookie_settings.h" 9 #include "chrome/browser/content_settings/cookie_settings.h"
10 #include "chrome/browser/content_settings/tab_specific_content_settings.h" 10 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
11 #include "chrome/browser/favicon/favicon_tab_helper.h" 11 #include "chrome/browser/favicon/favicon_tab_helper.h"
12 #include "chrome/browser/infobars/infobar_tab_helper.h" 12 #include "chrome/browser/infobars/infobar_tab_helper.h"
13 #include "chrome/browser/prefs/pref_service.h" 13 #include "chrome/browser/prefs/pref_service.h"
14 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h" 15 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
16 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper_delegate. h" 16 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper_delegate. h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h" 17 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
19 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 18 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
20 #include "chrome/common/chrome_notification_types.h" 19 #include "chrome/common/chrome_notification_types.h"
21 #include "chrome/common/content_settings.h" 20 #include "chrome/common/content_settings.h"
22 #include "chrome/common/pref_names.h" 21 #include "chrome/common/pref_names.h"
23 #include "chrome/common/render_messages.h" 22 #include "chrome/common/render_messages.h"
24 #include "content/public/browser/notification_service.h" 23 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/render_view_host.h" 24 #include "content/public/browser/render_view_host.h"
26 #include "content/public/browser/user_metrics.h" 25 #include "content/public/browser/user_metrics.h"
27 #include "content/public/browser/web_contents.h" 26 #include "content/public/browser/web_contents.h"
(...skipping 22 matching lines...) Expand all
50 if (entries[i].type == type) 49 if (entries[i].type == type)
51 return entries[i].id; 50 return entries[i].id;
52 } 51 }
53 return 0; 52 return 0;
54 } 53 }
55 54
56 } // namespace 55 } // namespace
57 56
58 class ContentSettingTitleAndLinkModel : public ContentSettingBubbleModel { 57 class ContentSettingTitleAndLinkModel : public ContentSettingBubbleModel {
59 public: 58 public:
60 ContentSettingTitleAndLinkModel(Browser* browser, 59 ContentSettingTitleAndLinkModel(Delegate* delegate,
61 TabContentsWrapper* tab_contents, 60 TabContentsWrapper* tab_contents,
62 Profile* profile, 61 Profile* profile,
63 ContentSettingsType content_type) 62 ContentSettingsType content_type)
64 : ContentSettingBubbleModel(tab_contents, profile, content_type), 63 : ContentSettingBubbleModel(tab_contents, profile, content_type),
65 browser_(browser) { 64 delegate_(delegate) {
66 // Notifications do not have a bubble. 65 // Notifications do not have a bubble.
67 DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS); 66 DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
68 SetBlockedResources(); 67 SetBlockedResources();
69 SetTitle(); 68 SetTitle();
70 SetManageLink(); 69 SetManageLink();
71 } 70 }
72 71
73 virtual ~ContentSettingTitleAndLinkModel() {} 72 virtual ~ContentSettingTitleAndLinkModel() {}
74 Browser* browser() const { return browser_; } 73 Delegate* delegate() const { return delegate_; }
75 74
76 private: 75 private:
77 void SetBlockedResources() { 76 void SetBlockedResources() {
78 TabSpecificContentSettings* settings = tab_contents()->content_settings(); 77 TabSpecificContentSettings* settings = tab_contents()->content_settings();
79 const std::set<std::string>& resources = settings->BlockedResourcesForType( 78 const std::set<std::string>& resources = settings->BlockedResourcesForType(
80 content_type()); 79 content_type());
81 for (std::set<std::string>::const_iterator it = resources.begin(); 80 for (std::set<std::string>::const_iterator it = resources.begin();
82 it != resources.end(); ++it) { 81 it != resources.end(); ++it) {
83 AddBlockedResource(*it); 82 AddBlockedResource(*it);
84 } 83 }
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_LINK}, 123 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_LINK},
125 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LINK}, 124 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LINK},
126 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_LINK}, 125 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_LINK},
127 {CONTENT_SETTINGS_TYPE_GEOLOCATION, IDS_GEOLOCATION_BUBBLE_MANAGE_LINK}, 126 {CONTENT_SETTINGS_TYPE_GEOLOCATION, IDS_GEOLOCATION_BUBBLE_MANAGE_LINK},
128 }; 127 };
129 set_manage_link(l10n_util::GetStringUTF8( 128 set_manage_link(l10n_util::GetStringUTF8(
130 GetIdForContentType(kLinkIDs, arraysize(kLinkIDs), content_type()))); 129 GetIdForContentType(kLinkIDs, arraysize(kLinkIDs), content_type())));
131 } 130 }
132 131
133 virtual void OnManageLinkClicked() { 132 virtual void OnManageLinkClicked() {
134 if (browser_) 133 if (delegate_)
135 browser_->ShowContentSettingsPage(content_type()); 134 delegate_->ShowContentSettingsPage(content_type());
136 } 135 }
137 136
138 Browser* browser_; 137 Delegate* delegate_;
139 }; 138 };
140 139
141 class ContentSettingTitleLinkAndCustomModel 140 class ContentSettingTitleLinkAndCustomModel
142 : public ContentSettingTitleAndLinkModel { 141 : public ContentSettingTitleAndLinkModel {
143 public: 142 public:
144 ContentSettingTitleLinkAndCustomModel(Browser* browser, 143 ContentSettingTitleLinkAndCustomModel(Delegate* delegate,
145 TabContentsWrapper* tab_contents, 144 TabContentsWrapper* tab_contents,
146 Profile* profile, 145 Profile* profile,
147 ContentSettingsType content_type) 146 ContentSettingsType content_type)
148 : ContentSettingTitleAndLinkModel( 147 : ContentSettingTitleAndLinkModel(
149 browser, tab_contents, profile, content_type) { 148 delegate, tab_contents, profile, content_type) {
150 SetCustomLink(); 149 SetCustomLink();
151 } 150 }
152 151
153 virtual ~ContentSettingTitleLinkAndCustomModel() {} 152 virtual ~ContentSettingTitleLinkAndCustomModel() {}
154 153
155 private: 154 private:
156 void SetCustomLink() { 155 void SetCustomLink() {
157 static const ContentSettingsTypeIdEntry kCustomIDs[] = { 156 static const ContentSettingsTypeIdEntry kCustomIDs[] = {
158 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_INFO}, 157 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_INFO},
159 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LOAD_ALL}, 158 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LOAD_ALL},
160 }; 159 };
161 int custom_link_id = 160 int custom_link_id =
162 GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type()); 161 GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type());
163 if (custom_link_id) 162 if (custom_link_id)
164 set_custom_link(l10n_util::GetStringUTF8(custom_link_id)); 163 set_custom_link(l10n_util::GetStringUTF8(custom_link_id));
165 } 164 }
166 165
167 virtual void OnCustomLinkClicked() {} 166 virtual void OnCustomLinkClicked() {}
168 }; 167 };
169 168
170 169
171 class ContentSettingSingleRadioGroup 170 class ContentSettingSingleRadioGroup
172 : public ContentSettingTitleLinkAndCustomModel { 171 : public ContentSettingTitleLinkAndCustomModel {
173 public: 172 public:
174 ContentSettingSingleRadioGroup(Browser* browser, 173 ContentSettingSingleRadioGroup(Delegate* delegate,
175 TabContentsWrapper* tab_contents, 174 TabContentsWrapper* tab_contents,
176 Profile* profile, 175 Profile* profile,
177 ContentSettingsType content_type) 176 ContentSettingsType content_type)
178 : ContentSettingTitleLinkAndCustomModel(browser, tab_contents, profile, 177 : ContentSettingTitleLinkAndCustomModel(delegate, tab_contents, profile,
179 content_type), 178 content_type),
180 block_setting_(CONTENT_SETTING_BLOCK), 179 block_setting_(CONTENT_SETTING_BLOCK),
181 selected_item_(0) { 180 selected_item_(0) {
182 SetRadioGroup(); 181 SetRadioGroup();
183 } 182 }
184 183
185 virtual ~ContentSettingSingleRadioGroup() { 184 virtual ~ContentSettingSingleRadioGroup() {
186 if (settings_changed()) { 185 if (settings_changed()) {
187 ContentSetting setting = 186 ContentSetting setting =
188 selected_item_ == 0 ? CONTENT_SETTING_ALLOW : block_setting_; 187 selected_item_ == 0 ? CONTENT_SETTING_ALLOW : block_setting_;
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 } 325 }
327 } 326 }
328 327
329 virtual void OnRadioClicked(int radio_index) { 328 virtual void OnRadioClicked(int radio_index) {
330 selected_item_ = radio_index; 329 selected_item_ = radio_index;
331 } 330 }
332 }; 331 };
333 332
334 class ContentSettingCookiesBubbleModel : public ContentSettingSingleRadioGroup { 333 class ContentSettingCookiesBubbleModel : public ContentSettingSingleRadioGroup {
335 public: 334 public:
336 ContentSettingCookiesBubbleModel(Browser* browser, 335 ContentSettingCookiesBubbleModel(Delegate* delegate,
337 TabContentsWrapper* tab_contents, 336 TabContentsWrapper* tab_contents,
338 Profile* profile, 337 Profile* profile,
339 ContentSettingsType content_type) 338 ContentSettingsType content_type)
340 : ContentSettingSingleRadioGroup( 339 : ContentSettingSingleRadioGroup(
341 browser, tab_contents, profile, content_type) { 340 delegate, tab_contents, profile, content_type) {
342 DCHECK_EQ(CONTENT_SETTINGS_TYPE_COOKIES, content_type); 341 DCHECK_EQ(CONTENT_SETTINGS_TYPE_COOKIES, content_type);
343 set_custom_link_enabled(true); 342 set_custom_link_enabled(true);
344 } 343 }
345 344
346 virtual ~ContentSettingCookiesBubbleModel() { 345 virtual ~ContentSettingCookiesBubbleModel() {
347 if (settings_changed()) { 346 if (settings_changed()) {
348 InfoBarTabHelper* infobar_helper = tab_contents()->infobar_tab_helper(); 347 InfoBarTabHelper* infobar_helper = tab_contents()->infobar_tab_helper();
349 infobar_helper->AddInfoBar( 348 infobar_helper->AddInfoBar(
350 new CollectedCookiesInfoBarDelegate(infobar_helper)); 349 new CollectedCookiesInfoBarDelegate(infobar_helper));
351 } 350 }
352 } 351 }
353 352
354 private: 353 private:
355 virtual void OnCustomLinkClicked() OVERRIDE { 354 virtual void OnCustomLinkClicked() OVERRIDE {
356 if (!tab_contents()) 355 if (!tab_contents())
357 return; 356 return;
358 content::NotificationService::current()->Notify( 357 content::NotificationService::current()->Notify(
359 chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN, 358 chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN,
360 content::Source<TabSpecificContentSettings>( 359 content::Source<TabSpecificContentSettings>(
361 tab_contents()->content_settings()), 360 tab_contents()->content_settings()),
362 content::NotificationService::NoDetails()); 361 content::NotificationService::NoDetails());
363 browser()->ShowCollectedCookiesDialog(tab_contents()); 362 delegate()->ShowCollectedCookiesDialog(tab_contents());
364 } 363 }
365 }; 364 };
366 365
367 class ContentSettingPluginBubbleModel : public ContentSettingSingleRadioGroup { 366 class ContentSettingPluginBubbleModel : public ContentSettingSingleRadioGroup {
368 public: 367 public:
369 ContentSettingPluginBubbleModel(Browser* browser, 368 ContentSettingPluginBubbleModel(Delegate* delegate,
370 TabContentsWrapper* tab_contents, 369 TabContentsWrapper* tab_contents,
371 Profile* profile, 370 Profile* profile,
372 ContentSettingsType content_type) 371 ContentSettingsType content_type)
373 : ContentSettingSingleRadioGroup( 372 : ContentSettingSingleRadioGroup(
374 browser, tab_contents, profile, content_type) { 373 delegate, tab_contents, profile, content_type) {
375 DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_PLUGINS); 374 DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_PLUGINS);
376 set_custom_link_enabled(tab_contents && tab_contents->content_settings()-> 375 set_custom_link_enabled(tab_contents && tab_contents->content_settings()->
377 load_plugins_link_enabled()); 376 load_plugins_link_enabled());
378 } 377 }
379 378
380 virtual ~ContentSettingPluginBubbleModel() {} 379 virtual ~ContentSettingPluginBubbleModel() {}
381 380
382 private: 381 private:
383 virtual void OnCustomLinkClicked() OVERRIDE { 382 virtual void OnCustomLinkClicked() OVERRIDE {
384 content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble")); 383 content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble"));
385 DCHECK(tab_contents()); 384 DCHECK(tab_contents());
386 RenderViewHost* host = tab_contents()->web_contents()->GetRenderViewHost(); 385 RenderViewHost* host = tab_contents()->web_contents()->GetRenderViewHost();
387 host->Send(new ChromeViewMsg_LoadBlockedPlugins(host->GetRoutingID())); 386 host->Send(new ChromeViewMsg_LoadBlockedPlugins(host->GetRoutingID()));
388 set_custom_link_enabled(false); 387 set_custom_link_enabled(false);
389 tab_contents()->content_settings()->set_load_plugins_link_enabled(false); 388 tab_contents()->content_settings()->set_load_plugins_link_enabled(false);
390 } 389 }
391 }; 390 };
392 391
393 class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup { 392 class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup {
394 public: 393 public:
395 ContentSettingPopupBubbleModel(Browser* browser, 394 ContentSettingPopupBubbleModel(Delegate* delegate,
396 TabContentsWrapper* tab_contents, 395 TabContentsWrapper* tab_contents,
397 Profile* profile, 396 Profile* profile,
398 ContentSettingsType content_type) 397 ContentSettingsType content_type)
399 : ContentSettingSingleRadioGroup( 398 : ContentSettingSingleRadioGroup(
400 browser, tab_contents, profile, content_type) { 399 delegate, tab_contents, profile, content_type) {
401 SetPopups(); 400 SetPopups();
402 } 401 }
403 402
404 virtual ~ContentSettingPopupBubbleModel() {} 403 virtual ~ContentSettingPopupBubbleModel() {}
405 404
406 private: 405 private:
407 void SetPopups() { 406 void SetPopups() {
408 std::vector<TabContentsWrapper*> blocked_contents; 407 std::vector<TabContentsWrapper*> blocked_contents;
409 tab_contents()->blocked_content_tab_helper()-> 408 tab_contents()->blocked_content_tab_helper()->
410 GetBlockedContents(&blocked_contents); 409 GetBlockedContents(&blocked_contents);
(...skipping 16 matching lines...) Expand all
427 if (tab_contents()) { 426 if (tab_contents()) {
428 tab_contents()->blocked_content_tab_helper()-> 427 tab_contents()->blocked_content_tab_helper()->
429 LaunchForContents(bubble_content().popup_items[index].tab_contents); 428 LaunchForContents(bubble_content().popup_items[index].tab_contents);
430 } 429 }
431 } 430 }
432 }; 431 };
433 432
434 class ContentSettingDomainListBubbleModel 433 class ContentSettingDomainListBubbleModel
435 : public ContentSettingTitleAndLinkModel { 434 : public ContentSettingTitleAndLinkModel {
436 public: 435 public:
437 ContentSettingDomainListBubbleModel(Browser* browser, 436 ContentSettingDomainListBubbleModel(Delegate* delegate,
438 TabContentsWrapper* tab_contents, 437 TabContentsWrapper* tab_contents,
439 Profile* profile, 438 Profile* profile,
440 ContentSettingsType content_type) 439 ContentSettingsType content_type)
441 : ContentSettingTitleAndLinkModel( 440 : ContentSettingTitleAndLinkModel(
442 browser, tab_contents, profile, content_type) { 441 delegate, tab_contents, profile, content_type) {
443 DCHECK_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION, content_type) << 442 DCHECK_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION, content_type) <<
444 "SetDomains currently only supports geolocation content type"; 443 "SetDomains currently only supports geolocation content type";
445 SetDomainsAndCustomLink(); 444 SetDomainsAndCustomLink();
446 } 445 }
447 446
448 virtual ~ContentSettingDomainListBubbleModel() {} 447 virtual ~ContentSettingDomainListBubbleModel() {}
449 448
450 private: 449 private:
451 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id) { 450 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id) {
452 if (!hosts.empty()) { 451 if (!hosts.empty()) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
503 CONTENT_SETTINGS_TYPE_GEOLOCATION, 502 CONTENT_SETTINGS_TYPE_GEOLOCATION,
504 std::string(), 503 std::string(),
505 CONTENT_SETTING_DEFAULT); 504 CONTENT_SETTING_DEFAULT);
506 } 505 }
507 } 506 }
508 }; 507 };
509 508
510 // static 509 // static
511 ContentSettingBubbleModel* 510 ContentSettingBubbleModel*
512 ContentSettingBubbleModel::CreateContentSettingBubbleModel( 511 ContentSettingBubbleModel::CreateContentSettingBubbleModel(
513 Browser* browser, 512 Delegate* delegate,
514 TabContentsWrapper* tab_contents, 513 TabContentsWrapper* tab_contents,
515 Profile* profile, 514 Profile* profile,
516 ContentSettingsType content_type) { 515 ContentSettingsType content_type) {
517 if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) { 516 if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
518 return new ContentSettingCookiesBubbleModel(browser, tab_contents, profile, 517 return new ContentSettingCookiesBubbleModel(delegate, tab_contents, profile,
519 content_type); 518 content_type);
520 } 519 }
521 if (content_type == CONTENT_SETTINGS_TYPE_POPUPS) { 520 if (content_type == CONTENT_SETTINGS_TYPE_POPUPS) {
522 return new ContentSettingPopupBubbleModel(browser, tab_contents, profile, 521 return new ContentSettingPopupBubbleModel(delegate, tab_contents, profile,
523 content_type); 522 content_type);
524 } 523 }
525 if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) { 524 if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
526 return new ContentSettingDomainListBubbleModel(browser, tab_contents, 525 return new ContentSettingDomainListBubbleModel(delegate, tab_contents,
527 profile, content_type); 526 profile, content_type);
528 } 527 }
529 if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) { 528 if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
530 return new ContentSettingPluginBubbleModel(browser, tab_contents, profile, 529 return new ContentSettingPluginBubbleModel(delegate, tab_contents, profile,
531 content_type); 530 content_type);
532 } 531 }
533 return new ContentSettingSingleRadioGroup(browser, tab_contents, profile, 532 return new ContentSettingSingleRadioGroup(delegate, tab_contents, profile,
534 content_type); 533 content_type);
535 } 534 }
536 535
537 ContentSettingBubbleModel::ContentSettingBubbleModel( 536 ContentSettingBubbleModel::ContentSettingBubbleModel(
538 TabContentsWrapper* tab_contents, 537 TabContentsWrapper* tab_contents,
539 Profile* profile, 538 Profile* profile,
540 ContentSettingsType content_type) 539 ContentSettingsType content_type)
541 : tab_contents_(tab_contents), 540 : tab_contents_(tab_contents),
542 profile_(profile), 541 profile_(profile),
543 content_type_(content_type) { 542 content_type_(content_type) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 tab_contents_ = NULL; 581 tab_contents_ = NULL;
583 break; 582 break;
584 case chrome::NOTIFICATION_PROFILE_DESTROYED: 583 case chrome::NOTIFICATION_PROFILE_DESTROYED:
585 DCHECK(source == content::Source<Profile>(profile_)); 584 DCHECK(source == content::Source<Profile>(profile_));
586 profile_ = NULL; 585 profile_ = NULL;
587 break; 586 break;
588 default: 587 default:
589 NOTREACHED(); 588 NOTREACHED();
590 } 589 }
591 } 590 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698