| Index: chrome/browser/search/local_ntp_source.cc
 | 
| diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
 | 
| index d1a46a43edc3f9e3d5d641e51f2a9d61bd55c9ba..e988450c3244f78c398ff9fee07761bb1db3e2ab 100644
 | 
| --- a/chrome/browser/search/local_ntp_source.cc
 | 
| +++ b/chrome/browser/search/local_ntp_source.cc
 | 
| @@ -4,11 +4,11 @@
 | 
|  
 | 
|  #include "chrome/browser/search/local_ntp_source.h"
 | 
|  
 | 
| -#include <stddef.h>
 | 
| -
 | 
|  #include "base/base64.h"
 | 
|  #include "base/command_line.h"
 | 
| +#include "base/feature_list.h"
 | 
|  #include "base/json/json_string_value_serializer.h"
 | 
| +#include "base/json/json_writer.h"
 | 
|  #include "base/logging.h"
 | 
|  #include "base/memory/ptr_util.h"
 | 
|  #include "base/memory/ref_counted_memory.h"
 | 
| @@ -16,8 +16,12 @@
 | 
|  #include "base/strings/stringprintf.h"
 | 
|  #include "base/values.h"
 | 
|  #include "build/build_config.h"
 | 
| +#include "chrome/browser/profiles/profile.h"
 | 
|  #include "chrome/browser/search/instant_io_context.h"
 | 
|  #include "chrome/browser/search/local_files_ntp_source.h"
 | 
| +#include "chrome/browser/search/one_google_bar/one_google_bar_data.h"
 | 
| +#include "chrome/browser/search/one_google_bar/one_google_bar_service.h"
 | 
| +#include "chrome/browser/search/one_google_bar/one_google_bar_service_factory.h"
 | 
|  #include "chrome/browser/search_engines/template_url_service_factory.h"
 | 
|  #include "chrome/browser/themes/theme_properties.h"
 | 
|  #include "chrome/browser/themes/theme_service.h"
 | 
| @@ -43,12 +47,20 @@
 | 
|  
 | 
|  namespace {
 | 
|  
 | 
| +base::Feature kOneGoogleBarOnLocalNtpFeature{"OneGoogleBarOnLocalNtp",
 | 
| +                                             base::FEATURE_DISABLED_BY_DEFAULT};
 | 
| +
 | 
|  // Signifies a locally constructed resource, i.e. not from grit/.
 | 
|  const int kLocalResource = -1;
 | 
|  
 | 
|  const char kConfigDataFilename[] = "config.js";
 | 
|  const char kThemeCSSFilename[] = "theme.css";
 | 
|  const char kMainHtmlFilename[] = "local-ntp.html";
 | 
| +const char kOneGoogleBarScriptFilename[] = "one-google.js";
 | 
| +const char kOneGoogleBarInHeadStyleFilename[] = "one-google/in-head.css";
 | 
| +const char kOneGoogleBarInHeadScriptFilename[] = "one-google/in-head.js";
 | 
| +const char kOneGoogleBarAfterBarScriptFilename[] = "one-google/after-bar.js";
 | 
| +const char kOneGoogleBarEndOfBodyScriptFilename[] = "one-google/end-of-body.js";
 | 
|  
 | 
|  const struct Resource{
 | 
|    const char* filename;
 | 
| @@ -63,6 +75,11 @@ const struct Resource{
 | 
|      {"images/close_3_mask.png", IDR_CLOSE_3_MASK, "image/png"},
 | 
|      {"images/close_4_button.png", IDR_CLOSE_4_BUTTON, "image/png"},
 | 
|      {"images/ntp_default_favicon.png", IDR_NTP_DEFAULT_FAVICON, "image/png"},
 | 
| +    {kOneGoogleBarScriptFilename, kLocalResource, "text/javascript"},
 | 
| +    {kOneGoogleBarInHeadStyleFilename, kLocalResource, "text/css"},
 | 
| +    {kOneGoogleBarInHeadScriptFilename, kLocalResource, "text/javascript"},
 | 
| +    {kOneGoogleBarAfterBarScriptFilename, kLocalResource, "text/javascript"},
 | 
| +    {kOneGoogleBarEndOfBodyScriptFilename, kLocalResource, "text/javascript"},
 | 
|  };
 | 
|  
 | 
|  // Strips any query parameters from the specified path.
 | 
| @@ -160,6 +177,16 @@ bool DefaultSearchProviderIsGoogleImpl(
 | 
|                                SEARCH_ENGINE_GOOGLE);
 | 
|  }
 | 
|  
 | 
| +std::unique_ptr<base::DictionaryValue> ConvertOGBDataToDict(
 | 
| +    const OneGoogleBarData& og) {
 | 
| +  auto result = base::MakeUnique<base::DictionaryValue>();
 | 
| +  // Only provide the html parts here. The js and css are injected separately
 | 
| +  // via <script src=...> and <link rel="stylesheet" href=...>.
 | 
| +  result->SetString("html", og.bar_html);
 | 
| +  result->SetString("end_of_body_html", og.end_of_body_html);
 | 
| +  return result;
 | 
| +}
 | 
| +
 | 
|  }  // namespace
 | 
|  
 | 
|  class LocalNtpSource::GoogleSearchProviderTracker
 | 
| @@ -205,11 +232,23 @@ class LocalNtpSource::GoogleSearchProviderTracker
 | 
|  
 | 
|  LocalNtpSource::LocalNtpSource(Profile* profile)
 | 
|      : profile_(profile),
 | 
| +      one_google_bar_service_(nullptr),
 | 
| +      one_google_bar_service_observer_(this),
 | 
|        default_search_provider_is_google_(false),
 | 
|        default_search_provider_is_google_io_thread_(false),
 | 
|        weak_ptr_factory_(this) {
 | 
|    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 | 
|  
 | 
| +  if (base::FeatureList::IsEnabled(kOneGoogleBarOnLocalNtpFeature)) {
 | 
| +    one_google_bar_service_ =
 | 
| +        OneGoogleBarServiceFactory::GetForProfile(profile_);
 | 
| +  }
 | 
| +
 | 
| +  // |one_google_bar_service_| is null in incognito, or when the feature is
 | 
| +  // disabled.
 | 
| +  if (one_google_bar_service_)
 | 
| +    one_google_bar_service_observer_.Add(one_google_bar_service_);
 | 
| +
 | 
|    TemplateURLService* template_url_service =
 | 
|        TemplateURLServiceFactory::GetForProfile(profile_);
 | 
|    if (template_url_service) {
 | 
| @@ -247,6 +286,46 @@ void LocalNtpSource::StartDataRequest(
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| +  if (base::StartsWith(stripped_path, "one-google",
 | 
| +                       base::CompareCase::SENSITIVE)) {
 | 
| +    if (!one_google_bar_service_) {
 | 
| +      callback.Run(nullptr);
 | 
| +      return;
 | 
| +    }
 | 
| +
 | 
| +    const base::Optional<OneGoogleBarData>& data =
 | 
| +        one_google_bar_service_->one_google_bar_data();
 | 
| +
 | 
| +    // The OneGoogleBar injector helper.
 | 
| +    if (stripped_path == kOneGoogleBarScriptFilename) {
 | 
| +      one_google_callbacks_.push_back(callback);
 | 
| +
 | 
| +      // If there already is (cached) OGB data, serve it immediately.
 | 
| +      if (data.has_value())
 | 
| +        ServeOneGoogleBar(*data);
 | 
| +
 | 
| +      // In any case, request a refresh.
 | 
| +      one_google_bar_service_->Refresh();
 | 
| +    } else {
 | 
| +      // The actual OneGoogleBar sources.
 | 
| +      std::string result;
 | 
| +      if (data.has_value()) {
 | 
| +        if (stripped_path == kOneGoogleBarInHeadStyleFilename) {
 | 
| +          result = data->in_head_style;
 | 
| +        } else if (stripped_path == kOneGoogleBarInHeadScriptFilename) {
 | 
| +          result = data->in_head_script;
 | 
| +        } else if (stripped_path == kOneGoogleBarAfterBarScriptFilename) {
 | 
| +          result = data->after_bar_script;
 | 
| +        } else if (stripped_path == kOneGoogleBarEndOfBodyScriptFilename) {
 | 
| +          result = data->end_of_body_script;
 | 
| +        }
 | 
| +      }
 | 
| +      callback.Run(base::RefCountedString::TakeString(&result));
 | 
| +    }
 | 
| +
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
|  #if !defined(GOOGLE_CHROME_BUILD)
 | 
|    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
 | 
|    if (command_line->HasSwitch(switches::kLocalNtpReload)) {
 | 
| @@ -343,17 +422,65 @@ std::string LocalNtpSource::GetContentSecurityPolicyScriptSrc() const {
 | 
|           GetIntegritySha256Value(
 | 
|               GetConfigData(default_search_provider_is_google_io_thread_)) +
 | 
|           "' "
 | 
| -         "'sha256-g38WaUaxnOIWY7E2LtLZ5ff9r5sn1dBj80jevt/kmx0=';";
 | 
| +         "'sha256-ROPmcormZEipZzy3Ff+o345FFrhHWsAZjBpGIyZzCYY=';";
 | 
|  }
 | 
|  
 | 
|  std::string LocalNtpSource::GetContentSecurityPolicyChildSrc() const {
 | 
|    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 | 
|  
 | 
| -  // Allow embedding of most visited iframes.
 | 
| +  if (one_google_bar_service_) {
 | 
| +    // Allow embedding of the most visited iframe, as well as the account
 | 
| +    // switcher and the notifications dropdown from the One Google Bar.
 | 
| +    // TODO(treib): Figure out a way to also allow staging instances.
 | 
| +    return base::StringPrintf(
 | 
| +        "child-src %s https://accounts.google.com/ https://docs.google.com "
 | 
| +        "https://notifications.google.com;",
 | 
| +        chrome::kChromeSearchMostVisitedUrl);
 | 
| +  }
 | 
| +  // Allow embedding of the most visited iframe.
 | 
|    return base::StringPrintf("child-src %s;",
 | 
|                              chrome::kChromeSearchMostVisitedUrl);
 | 
|  }
 | 
|  
 | 
| +void LocalNtpSource::OnOneGoogleBarDataChanged() {
 | 
| +  const base::Optional<OneGoogleBarData>& data =
 | 
| +      one_google_bar_service_->one_google_bar_data();
 | 
| +  if (data.has_value())
 | 
| +    ServeOneGoogleBar(*data);
 | 
| +  else
 | 
| +    ServeNullOneGoogleBar();
 | 
| +}
 | 
| +
 | 
| +void LocalNtpSource::OnOneGoogleBarFetchFailed() {
 | 
| +  ServeNullOneGoogleBar();
 | 
| +}
 | 
| +
 | 
| +void LocalNtpSource::OnOneGoogleBarServiceShuttingDown() {
 | 
| +  one_google_bar_service_observer_.RemoveAll();
 | 
| +  one_google_bar_service_ = nullptr;
 | 
| +}
 | 
| +
 | 
| +void LocalNtpSource::ServeOneGoogleBar(const OneGoogleBarData& data) {
 | 
| +  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 | 
| +
 | 
| +  if (one_google_callbacks_.empty())
 | 
| +    return;
 | 
| +
 | 
| +  std::string json;
 | 
| +  base::JSONWriter::Write(*ConvertOGBDataToDict(data), &json);
 | 
| +  for (auto& callback : one_google_callbacks_) {
 | 
| +    std::string data = "var og = " + json + ";";
 | 
| +    callback.Run(base::RefCountedString::TakeString(&data));
 | 
| +  }
 | 
| +  one_google_callbacks_.clear();
 | 
| +}
 | 
| +
 | 
| +void LocalNtpSource::ServeNullOneGoogleBar() {
 | 
| +  for (auto& callback : one_google_callbacks_)
 | 
| +    callback.Run(nullptr);
 | 
| +  one_google_callbacks_.clear();
 | 
| +}
 | 
| +
 | 
|  void LocalNtpSource::DefaultSearchProviderIsGoogleChanged(bool is_google) {
 | 
|    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 | 
|  
 | 
| 
 |