Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / search / instant_service.cc
blob441a997298fd5267a96eedbe300f08585f263965
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/search/instant_service.h"
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/favicon/fallback_icon_service_factory.h"
9 #include "chrome/browser/favicon/favicon_service_factory.h"
10 #include "chrome/browser/history/top_sites_factory.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/search/instant_io_context.h"
13 #include "chrome/browser/search/instant_service_observer.h"
14 #include "chrome/browser/search/most_visited_iframe_source.h"
15 #include "chrome/browser/search/search.h"
16 #include "chrome/browser/search/suggestions/suggestions_source.h"
17 #include "chrome/browser/search_engines/template_url_service_factory.h"
18 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
19 #include "chrome/browser/themes/theme_properties.h"
20 #include "chrome/browser/themes/theme_service.h"
21 #include "chrome/browser/themes/theme_service_factory.h"
22 #include "chrome/browser/thumbnails/thumbnail_list_source.h"
23 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
24 #include "chrome/browser/ui/webui/fallback_icon_source.h"
25 #include "chrome/browser/ui/webui/favicon_source.h"
26 #include "chrome/browser/ui/webui/large_icon_source.h"
27 #include "chrome/browser/ui/webui/ntp/thumbnail_source.h"
28 #include "chrome/browser/ui/webui/theme_source.h"
29 #include "chrome/common/render_messages.h"
30 #include "components/favicon/core/fallback_icon_service.h"
31 #include "components/favicon/core/favicon_service.h"
32 #include "components/history/core/browser/top_sites.h"
33 #include "components/keyed_service/core/service_access_type.h"
34 #include "components/search_engines/template_url_service.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/notification_service.h"
37 #include "content/public/browser/notification_types.h"
38 #include "content/public/browser/render_process_host.h"
39 #include "content/public/browser/url_data_source.h"
40 #include "grit/theme_resources.h"
41 #include "third_party/skia/include/core/SkColor.h"
42 #include "ui/gfx/color_utils.h"
43 #include "ui/gfx/image/image_skia.h"
44 #include "ui/gfx/sys_color_change_listener.h"
46 #if !defined(OS_ANDROID)
47 #include "chrome/browser/search/local_ntp_source.h"
48 #endif
50 namespace {
52 const int kSectionBorderAlphaTransparency = 80;
54 // Converts SkColor to RGBAColor
55 RGBAColor SkColorToRGBAColor(const SkColor& sKColor) {
56 RGBAColor color;
57 color.r = SkColorGetR(sKColor);
58 color.g = SkColorGetG(sKColor);
59 color.b = SkColorGetB(sKColor);
60 color.a = SkColorGetA(sKColor);
61 return color;
64 } // namespace
66 InstantService::InstantService(Profile* profile)
67 : profile_(profile),
68 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile_)),
69 omnibox_start_margin_(chrome::kDisableStartMargin),
70 weak_ptr_factory_(this) {
71 // The initialization below depends on a typical set of browser threads. Skip
72 // it if we are running in a unit test without the full suite.
73 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI))
74 return;
76 // This depends on the existence of the typical browser threads. Therefore it
77 // is only instantiated here (after the check for a UI thread above).
78 instant_io_context_ = new InstantIOContext();
80 previous_google_base_url_ =
81 GURL(UIThreadSearchTermsData(profile).GoogleBaseURLValue());
83 // TemplateURLService is NULL by default in tests.
84 if (template_url_service_) {
85 template_url_service_->AddObserver(this);
86 const TemplateURL* default_search_provider =
87 template_url_service_->GetDefaultSearchProvider();
88 if (default_search_provider) {
89 previous_default_search_provider_.reset(
90 new TemplateURLData(default_search_provider->data()));
94 ResetInstantSearchPrerenderer();
96 registrar_.Add(this,
97 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
98 content::NotificationService::AllSources());
99 registrar_.Add(this,
100 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
101 content::NotificationService::AllSources());
103 scoped_refptr<history::TopSites> top_sites =
104 TopSitesFactory::GetForProfile(profile_);
105 if (top_sites)
106 top_sites->AddObserver(this);
108 if (profile_ && profile_->GetResourceContext()) {
109 content::BrowserThread::PostTask(
110 content::BrowserThread::IO, FROM_HERE,
111 base::Bind(&InstantIOContext::SetUserDataOnIO,
112 profile->GetResourceContext(), instant_io_context_));
115 // Set up the data sources that Instant uses on the NTP.
116 #if defined(ENABLE_THEMES)
117 // Listen for theme installation.
118 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
119 content::Source<ThemeService>(
120 ThemeServiceFactory::GetForProfile(profile_)));
122 content::URLDataSource::Add(profile_, new ThemeSource(profile_));
123 #endif // defined(ENABLE_THEMES)
125 // TODO(aurimas) remove this #if once instant_service.cc is no longer compiled
126 // on Android.
127 #if !defined(OS_ANDROID)
128 content::URLDataSource::Add(profile_, new LocalNtpSource(profile_));
129 content::URLDataSource::Add(profile_, new ThumbnailSource(profile_, false));
130 content::URLDataSource::Add(profile_, new ThumbnailSource(profile_, true));
131 content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_));
132 #endif // !defined(OS_ANDROID)
134 favicon::FaviconService* favicon_service =
135 FaviconServiceFactory::GetForProfile(profile_,
136 ServiceAccessType::EXPLICIT_ACCESS);
137 favicon::FallbackIconService* fallback_icon_service =
138 FallbackIconServiceFactory::GetForBrowserContext(profile_);
140 content::URLDataSource::Add(profile_,
141 new LargeIconSource(favicon_service, fallback_icon_service));
142 content::URLDataSource::Add(
143 profile_, new FallbackIconSource(fallback_icon_service));
144 content::URLDataSource::Add(
145 profile_, new FaviconSource(profile_, FaviconSource::FAVICON));
146 content::URLDataSource::Add(profile_, new MostVisitedIframeSource());
147 content::URLDataSource::Add(
148 profile_, new suggestions::SuggestionsSource(profile_));
151 InstantService::~InstantService() {
152 if (template_url_service_)
153 template_url_service_->RemoveObserver(this);
156 void InstantService::AddInstantProcess(int process_id) {
157 process_ids_.insert(process_id);
159 if (instant_io_context_.get()) {
160 content::BrowserThread::PostTask(
161 content::BrowserThread::IO, FROM_HERE,
162 base::Bind(&InstantIOContext::AddInstantProcessOnIO,
163 instant_io_context_, process_id));
167 bool InstantService::IsInstantProcess(int process_id) const {
168 return process_ids_.find(process_id) != process_ids_.end();
171 void InstantService::AddObserver(InstantServiceObserver* observer) {
172 observers_.AddObserver(observer);
175 void InstantService::RemoveObserver(InstantServiceObserver* observer) {
176 observers_.RemoveObserver(observer);
179 void InstantService::DeleteMostVisitedItem(const GURL& url) {
180 scoped_refptr<history::TopSites> top_sites =
181 TopSitesFactory::GetForProfile(profile_);
182 if (!top_sites)
183 return;
185 top_sites->AddBlacklistedURL(url);
188 void InstantService::UndoMostVisitedDeletion(const GURL& url) {
189 scoped_refptr<history::TopSites> top_sites =
190 TopSitesFactory::GetForProfile(profile_);
191 if (!top_sites)
192 return;
194 top_sites->RemoveBlacklistedURL(url);
197 void InstantService::UndoAllMostVisitedDeletions() {
198 scoped_refptr<history::TopSites> top_sites =
199 TopSitesFactory::GetForProfile(profile_);
200 if (!top_sites)
201 return;
203 top_sites->ClearBlacklistedURLs();
206 void InstantService::UpdateThemeInfo() {
207 // Update theme background info.
208 // Initialize |theme_info| if necessary.
209 if (!theme_info_)
210 OnThemeChanged(ThemeServiceFactory::GetForProfile(profile_));
211 else
212 OnThemeChanged(NULL);
215 void InstantService::UpdateMostVisitedItemsInfo() {
216 NotifyAboutMostVisitedItems();
219 void InstantService::Shutdown() {
220 process_ids_.clear();
222 if (instant_io_context_.get()) {
223 content::BrowserThread::PostTask(
224 content::BrowserThread::IO, FROM_HERE,
225 base::Bind(&InstantIOContext::ClearInstantProcessesOnIO,
226 instant_io_context_));
229 scoped_refptr<history::TopSites> top_sites =
230 TopSitesFactory::GetForProfile(profile_);
231 if (top_sites)
232 top_sites->RemoveObserver(this);
234 instant_io_context_ = NULL;
237 void InstantService::Observe(int type,
238 const content::NotificationSource& source,
239 const content::NotificationDetails& details) {
240 switch (type) {
241 case content::NOTIFICATION_RENDERER_PROCESS_CREATED:
242 SendSearchURLsToRenderer(
243 content::Source<content::RenderProcessHost>(source).ptr());
244 break;
245 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
246 OnRendererProcessTerminated(
247 content::Source<content::RenderProcessHost>(source)->GetID());
248 break;
249 #if defined(ENABLE_THEMES)
250 case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: {
251 OnThemeChanged(content::Source<ThemeService>(source).ptr());
252 break;
254 #endif // defined(ENABLE_THEMES)
255 default:
256 NOTREACHED() << "Unexpected notification type in InstantService.";
260 void InstantService::SendSearchURLsToRenderer(content::RenderProcessHost* rph) {
261 rph->Send(new ChromeViewMsg_SetSearchURLs(
262 chrome::GetSearchURLs(profile_), chrome::GetNewTabPageURL(profile_)));
265 void InstantService::OnOmniboxStartMarginChanged(int start_margin) {
266 omnibox_start_margin_ = start_margin;
267 FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
268 OmniboxStartMarginChanged(omnibox_start_margin_));
271 void InstantService::OnRendererProcessTerminated(int process_id) {
272 process_ids_.erase(process_id);
274 if (instant_io_context_.get()) {
275 content::BrowserThread::PostTask(
276 content::BrowserThread::IO, FROM_HERE,
277 base::Bind(&InstantIOContext::RemoveInstantProcessOnIO,
278 instant_io_context_, process_id));
282 void InstantService::OnMostVisitedItemsReceived(
283 const history::MostVisitedURLList& data) {
284 history::MostVisitedURLList reordered_data(data);
285 std::vector<InstantMostVisitedItem> new_most_visited_items;
286 for (size_t i = 0; i < reordered_data.size(); i++) {
287 const history::MostVisitedURL& url = reordered_data[i];
288 InstantMostVisitedItem item;
289 item.url = url.url;
290 item.title = url.title;
291 new_most_visited_items.push_back(item);
294 most_visited_items_ = new_most_visited_items;
295 NotifyAboutMostVisitedItems();
298 void InstantService::NotifyAboutMostVisitedItems() {
299 FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
300 MostVisitedItemsChanged(most_visited_items_));
303 void InstantService::OnThemeChanged(ThemeService* theme_service) {
304 if (!theme_service) {
305 DCHECK(theme_info_.get());
306 FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
307 ThemeInfoChanged(*theme_info_));
308 return;
311 // Get theme information from theme service.
312 theme_info_.reset(new ThemeBackgroundInfo());
314 // Get if the current theme is the default theme.
315 theme_info_->using_default_theme = theme_service->UsingDefaultTheme();
317 // Get theme colors.
318 SkColor background_color =
319 theme_service->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND);
320 SkColor text_color =
321 theme_service->GetColor(ThemeProperties::COLOR_NTP_TEXT);
322 SkColor link_color =
323 theme_service->GetColor(ThemeProperties::COLOR_NTP_LINK);
324 SkColor text_color_light =
325 theme_service->GetColor(ThemeProperties::COLOR_NTP_TEXT_LIGHT);
326 SkColor header_color =
327 theme_service->GetColor(ThemeProperties::COLOR_NTP_HEADER);
328 // Generate section border color from the header color.
329 SkColor section_border_color =
330 SkColorSetARGB(kSectionBorderAlphaTransparency,
331 SkColorGetR(header_color),
332 SkColorGetG(header_color),
333 SkColorGetB(header_color));
335 // Invert colors if needed.
336 if (gfx::IsInvertedColorScheme()) {
337 background_color = color_utils::InvertColor(background_color);
338 text_color = color_utils::InvertColor(text_color);
339 link_color = color_utils::InvertColor(link_color);
340 text_color_light = color_utils::InvertColor(text_color_light);
341 header_color = color_utils::InvertColor(header_color);
342 section_border_color = color_utils::InvertColor(section_border_color);
345 // Set colors.
346 theme_info_->background_color = SkColorToRGBAColor(background_color);
347 theme_info_->text_color = SkColorToRGBAColor(text_color);
348 theme_info_->link_color = SkColorToRGBAColor(link_color);
349 theme_info_->text_color_light = SkColorToRGBAColor(text_color_light);
350 theme_info_->header_color = SkColorToRGBAColor(header_color);
351 theme_info_->section_border_color = SkColorToRGBAColor(section_border_color);
353 int logo_alternate = theme_service->GetDisplayProperty(
354 ThemeProperties::NTP_LOGO_ALTERNATE);
355 theme_info_->logo_alternate = logo_alternate == 1;
357 if (theme_service->HasCustomImage(IDR_THEME_NTP_BACKGROUND)) {
358 // Set theme id for theme background image url.
359 theme_info_->theme_id = theme_service->GetThemeID();
361 // Set theme background image horizontal alignment.
362 int alignment = theme_service->GetDisplayProperty(
363 ThemeProperties::NTP_BACKGROUND_ALIGNMENT);
364 if (alignment & ThemeProperties::ALIGN_LEFT)
365 theme_info_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_LEFT;
366 else if (alignment & ThemeProperties::ALIGN_RIGHT)
367 theme_info_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_RIGHT;
368 else
369 theme_info_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
371 // Set theme background image vertical alignment.
372 if (alignment & ThemeProperties::ALIGN_TOP)
373 theme_info_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_TOP;
374 else if (alignment & ThemeProperties::ALIGN_BOTTOM)
375 theme_info_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_BOTTOM;
376 else
377 theme_info_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
379 // Set theme backgorund image tiling.
380 int tiling = theme_service->GetDisplayProperty(
381 ThemeProperties::NTP_BACKGROUND_TILING);
382 switch (tiling) {
383 case ThemeProperties::NO_REPEAT:
384 theme_info_->image_tiling = THEME_BKGRND_IMAGE_NO_REPEAT;
385 break;
386 case ThemeProperties::REPEAT_X:
387 theme_info_->image_tiling = THEME_BKGRND_IMAGE_REPEAT_X;
388 break;
389 case ThemeProperties::REPEAT_Y:
390 theme_info_->image_tiling = THEME_BKGRND_IMAGE_REPEAT_Y;
391 break;
392 case ThemeProperties::REPEAT:
393 theme_info_->image_tiling = THEME_BKGRND_IMAGE_REPEAT;
394 break;
397 // Set theme background image height.
398 gfx::ImageSkia* image = theme_service->GetImageSkiaNamed(
399 IDR_THEME_NTP_BACKGROUND);
400 DCHECK(image);
401 theme_info_->image_height = image->height();
403 theme_info_->has_attribution =
404 theme_service->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION);
407 FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
408 ThemeInfoChanged(*theme_info_));
411 void InstantService::OnTemplateURLServiceChanged() {
412 // Check whether the default search provider was changed.
413 const TemplateURL* template_url =
414 template_url_service_->GetDefaultSearchProvider();
415 bool default_search_provider_changed = !TemplateURL::MatchesData(
416 template_url, previous_default_search_provider_.get(),
417 UIThreadSearchTermsData(profile_));
418 if (default_search_provider_changed) {
419 previous_default_search_provider_.reset(
420 template_url ? new TemplateURLData(template_url->data()) : NULL);
423 // Note that, even if the TemplateURL for the Default Search Provider has not
424 // changed, the effective URLs might change if they reference the Google base
425 // URL. The TemplateURLService will notify us when the effective URL changes
426 // in this way but it's up to us to do the work to check both.
427 bool google_base_url_domain_changed = false;
428 GURL google_base_url(UIThreadSearchTermsData(profile_).GoogleBaseURLValue());
429 if (google_base_url != previous_google_base_url_) {
430 previous_google_base_url_ = google_base_url;
431 if (template_url && template_url->HasGoogleBaseURLs(
432 UIThreadSearchTermsData(profile_)))
433 google_base_url_domain_changed = true;
436 if (default_search_provider_changed || google_base_url_domain_changed) {
437 ResetInstantSearchPrerenderer();
438 FOR_EACH_OBSERVER(
439 InstantServiceObserver, observers_,
440 DefaultSearchProviderChanged(google_base_url_domain_changed));
444 void InstantService::TopSitesLoaded(history::TopSites* top_sites) {
447 void InstantService::TopSitesChanged(history::TopSites* top_sites) {
448 top_sites->GetMostVisitedURLs(
449 base::Bind(&InstantService::OnMostVisitedItemsReceived,
450 weak_ptr_factory_.GetWeakPtr()),
451 false);
454 void InstantService::ResetInstantSearchPrerenderer() {
455 if (!chrome::ShouldPrefetchSearchResults())
456 return;
458 GURL url(chrome::GetSearchResultPrefetchBaseURL(profile_));
459 instant_prerenderer_.reset(
460 url.is_valid() ? new InstantSearchPrerenderer(profile_, url) : NULL);