<commit_before>// 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/prerender/prerender_field_trial.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/common/chrome_switches.h"

namespace prerender {

void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
  enum PrerenderOption {
    PRERENDER_OPTION_AUTO,
    PRERENDER_OPTION_DISABLED,
    PRERENDER_OPTION_ENABLED,
    PRERENDER_OPTION_PREFETCH_ONLY,
  };

  PrerenderOption prerender_option = PRERENDER_OPTION_AUTO;
  if (command_line.HasSwitch(switches::kPrerender)) {
    const std::string switch_value =
        command_line.GetSwitchValueASCII(switches::kPrerender);

    if (switch_value == switches::kPrerenderSwitchValueAuto) {
      prerender_option = PRERENDER_OPTION_AUTO;
    } else if (switch_value == switches::kPrerenderSwitchValueDisabled) {
      prerender_option = PRERENDER_OPTION_DISABLED;
    } else if (switch_value.empty() ||
               switch_value == switches::kPrerenderSwitchValueEnabled) {
      // The empty string means the option was provided with no value, and that
      // means enable.
      prerender_option = PRERENDER_OPTION_ENABLED;
    } else if (switch_value == switches::kPrerenderSwitchValuePrefetchOnly) {
      prerender_option = PRERENDER_OPTION_PREFETCH_ONLY;
    } else {
      prerender_option = PRERENDER_OPTION_DISABLED;
      LOG(ERROR) << "Invalid --prerender option received on command line: "
                 << switch_value;
      LOG(ERROR) << "Disabling prerendering!";
    }
  }

  switch (prerender_option) {
    case PRERENDER_OPTION_AUTO: {
      const base::FieldTrial::Probability kPrefetchDivisor = 1000;
      const base::FieldTrial::Probability kYesPrefetchProbability = 500;
      scoped_refptr<base::FieldTrial> trial(
          new base::FieldTrial("Prefetch", kPrefetchDivisor,
                               "ContentPrefetchDisabled", 2011, 6, 30));
      const int kNoPrefetchGroup = trial->kDefaultGroupNumber;
      trial->AppendGroup("ContentPrefetchEnabled", kYesPrefetchProbability);
      const int kTrialGroup = trial->group();
      ResourceDispatcherHost::set_is_prefetch_enabled(
          kTrialGroup != kNoPrefetchGroup);

      // There is currently no prerendering field trial.
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    }
    case PRERENDER_OPTION_DISABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(false);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    case PRERENDER_OPTION_ENABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
      break;
    case PRERENDER_OPTION_PREFETCH_ONLY:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    default:
      NOTREACHED();
  }

  UMA_HISTOGRAM_ENUMERATION("Prerender.Sessions",
                            PrerenderManager::GetMode(),
                            PrerenderManager::PRERENDER_MODE_MAX);
}

}  // namespace prerender
<commit_msg>Add field trial (at 0%) for prerender<commit_after>// 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/prerender/prerender_field_trial.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/common/chrome_switches.h"

namespace prerender {

void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
  enum PrerenderOption {
    PRERENDER_OPTION_AUTO,
    PRERENDER_OPTION_DISABLED,
    PRERENDER_OPTION_ENABLED,
    PRERENDER_OPTION_PREFETCH_ONLY,
  };

  PrerenderOption prerender_option = PRERENDER_OPTION_AUTO;
  if (command_line.HasSwitch(switches::kPrerender)) {
    const std::string switch_value =
        command_line.GetSwitchValueASCII(switches::kPrerender);

    if (switch_value == switches::kPrerenderSwitchValueAuto) {
      prerender_option = PRERENDER_OPTION_AUTO;
    } else if (switch_value == switches::kPrerenderSwitchValueDisabled) {
      prerender_option = PRERENDER_OPTION_DISABLED;
    } else if (switch_value.empty() ||
               switch_value == switches::kPrerenderSwitchValueEnabled) {
      // The empty string means the option was provided with no value, and that
      // means enable.
      prerender_option = PRERENDER_OPTION_ENABLED;
    } else if (switch_value == switches::kPrerenderSwitchValuePrefetchOnly) {
      prerender_option = PRERENDER_OPTION_PREFETCH_ONLY;
    } else {
      prerender_option = PRERENDER_OPTION_DISABLED;
      LOG(ERROR) << "Invalid --prerender option received on command line: "
                 << switch_value;
      LOG(ERROR) << "Disabling prerendering!";
    }
  }

  switch (prerender_option) {
    case PRERENDER_OPTION_AUTO: {
      const base::FieldTrial::Probability kPrefetchDivisor = 1000;
      const base::FieldTrial::Probability kYesPrefetchProbability = 500;
      const base::FieldTrial::Probability kPrerenderProbability = 0;

      scoped_refptr<base::FieldTrial> trial(
          new base::FieldTrial("Prefetch", kPrefetchDivisor,
                               "ContentPrefetchDisabled", 2011, 6, 30));

      const int kNoPrefetchGroup = trial->kDefaultGroupNumber;
      const int kYesPrefetchGroup =
          trial->AppendGroup("ContentPrefetchEnabled", kYesPrefetchProbability);
      const int kPrerenderGroup =
          trial->AppendGroup("ContentPrefetchPrerender", kPrerenderProbability);
      const int trial_group = trial->group();
      if (trial_group == kYesPrefetchGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP);
      } else if (trial_group == kNoPrefetchGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      } else if (trial_group == kPrerenderGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP);
      } else {
        NOTREACHED();
      }
      break;
    }
    case PRERENDER_OPTION_DISABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(false);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    case PRERENDER_OPTION_ENABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
      break;
    case PRERENDER_OPTION_PREFETCH_ONLY:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    default:
      NOTREACHED();
  }

  UMA_HISTOGRAM_ENUMERATION("Prerender.Sessions",
                            PrerenderManager::GetMode(),
                            PrerenderManager::PRERENDER_MODE_MAX);
}

}  // namespace prerender
<|endoftext|>


<commit_before>// 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/prerender/prerender_field_trial.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/common/chrome_switches.h"

namespace prerender {

void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
  enum PrerenderOption {
    PRERENDER_OPTION_AUTO,
    PRERENDER_OPTION_DISABLED,
    PRERENDER_OPTION_ENABLED,
    PRERENDER_OPTION_PREFETCH_ONLY,
  };

  PrerenderOption prerender_option = PRERENDER_OPTION_AUTO;
  if (command_line.HasSwitch(switches::kPrerender)) {
    const std::string switch_value =
        command_line.GetSwitchValueASCII(switches::kPrerender);

    if (switch_value == switches::kPrerenderSwitchValueAuto) {
#if defined(OS_CHROMEOS)
      // Prerender is temporarily disabled on CrOS.
      // http://crosbug.com/12483
      prerender_option = PRERENDER_OPTION_DISABLED;
#else
      prerender_option = PRERENDER_OPTION_AUTO;
#endif
    } else if (switch_value == switches::kPrerenderSwitchValueDisabled) {
      prerender_option = PRERENDER_OPTION_DISABLED;
    } else if (switch_value.empty() ||
               switch_value == switches::kPrerenderSwitchValueEnabled) {
      // The empty string means the option was provided with no value, and that
      // means enable.
      prerender_option = PRERENDER_OPTION_ENABLED;
    } else if (switch_value == switches::kPrerenderSwitchValuePrefetchOnly) {
      prerender_option = PRERENDER_OPTION_PREFETCH_ONLY;
    } else {
      prerender_option = PRERENDER_OPTION_DISABLED;
      LOG(ERROR) << "Invalid --prerender option received on command line: "
                 << switch_value;
      LOG(ERROR) << "Disabling prerendering!";
    }
  }

  switch (prerender_option) {
    case PRERENDER_OPTION_AUTO: {
      const base::FieldTrial::Probability kPrefetchDivisor = 1000;
      const base::FieldTrial::Probability kYesPrefetchProbability = 0;
      const base::FieldTrial::Probability kPrerenderExp1Probability = 0;
      const base::FieldTrial::Probability kPrerenderControl1Probability = 0;
      const base::FieldTrial::Probability kPrerenderExp2Probability = 0;
      const base::FieldTrial::Probability kPrerenderControl2Probability = 0;

      scoped_refptr<base::FieldTrial> trial(
          new base::FieldTrial("Prefetch", kPrefetchDivisor,
                               "ContentPrefetchDisabled", 2011, 6, 30));

      const int kNoPrefetchGroup = trial->kDefaultGroupNumber;
      const int kYesPrefetchGroup =
          trial->AppendGroup("ContentPrefetchEnabled", kYesPrefetchProbability);
      const int kPrerenderExperiment1Group =
          trial->AppendGroup("ContentPrefetchPrerender1",
                             kPrerenderExp1Probability);
      const int kPrerenderControl1Group =
          trial->AppendGroup("ContentPrefetchPrerenderControl1",
                             kPrerenderControl1Probability);
      const int kPrerenderExperiment2Group =
          trial->AppendGroup("ContentPrefetchPrerender2",
                             kPrerenderExp2Probability);
      const int kPrerenderControl2Group =
          trial->AppendGroup("ContentPrefetchPrerenderControl2",
                             kPrerenderControl2Probability);
      const int trial_group = trial->group();
      if (trial_group == kYesPrefetchGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      } else if (trial_group == kNoPrefetchGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_DISABLED);
      } else if (trial_group == kPrerenderExperiment1Group ||
                 trial_group == kPrerenderExperiment2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP);
      } else if (trial_group == kPrerenderControl1Group ||
                 trial_group == kPrerenderControl2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP);
      } else {
        NOTREACHED();
      }
      break;
    }
    case PRERENDER_OPTION_DISABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(false);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    case PRERENDER_OPTION_ENABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
      break;
    case PRERENDER_OPTION_PREFETCH_ONLY:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    default:
      NOTREACHED();
  }

  UMA_HISTOGRAM_ENUMERATION("Prerender.Sessions",
                            PrerenderManager::GetMode(),
                            PrerenderManager::PRERENDER_MODE_MAX);
}

}  // namespace prerender
<commit_msg>Revert 83340 - Disable prerender experiment and control group.This is only being landed so it can be merged into the 472 branch, and will be reverted on trunk quickly.BUG=79804TEST=NoneReview URL: http://codereview.chromium.org/6893067 TBR=cbentzel@chromium.org<commit_after>// 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/prerender/prerender_field_trial.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/common/chrome_switches.h"

namespace prerender {

void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
  enum PrerenderOption {
    PRERENDER_OPTION_AUTO,
    PRERENDER_OPTION_DISABLED,
    PRERENDER_OPTION_ENABLED,
    PRERENDER_OPTION_PREFETCH_ONLY,
  };

  PrerenderOption prerender_option = PRERENDER_OPTION_AUTO;
  if (command_line.HasSwitch(switches::kPrerender)) {
    const std::string switch_value =
        command_line.GetSwitchValueASCII(switches::kPrerender);

    if (switch_value == switches::kPrerenderSwitchValueAuto) {
#if defined(OS_CHROMEOS)
      // Prerender is temporarily disabled on CrOS.
      // http://crosbug.com/12483
      prerender_option = PRERENDER_OPTION_DISABLED;
#else
      prerender_option = PRERENDER_OPTION_AUTO;
#endif
    } else if (switch_value == switches::kPrerenderSwitchValueDisabled) {
      prerender_option = PRERENDER_OPTION_DISABLED;
    } else if (switch_value.empty() ||
               switch_value == switches::kPrerenderSwitchValueEnabled) {
      // The empty string means the option was provided with no value, and that
      // means enable.
      prerender_option = PRERENDER_OPTION_ENABLED;
    } else if (switch_value == switches::kPrerenderSwitchValuePrefetchOnly) {
      prerender_option = PRERENDER_OPTION_PREFETCH_ONLY;
    } else {
      prerender_option = PRERENDER_OPTION_DISABLED;
      LOG(ERROR) << "Invalid --prerender option received on command line: "
                 << switch_value;
      LOG(ERROR) << "Disabling prerendering!";
    }
  }

  switch (prerender_option) {
    case PRERENDER_OPTION_AUTO: {
      const base::FieldTrial::Probability kPrefetchDivisor = 1000;
      const base::FieldTrial::Probability kYesPrefetchProbability = 0;
      const base::FieldTrial::Probability kPrerenderExp1Probability = 400;
      const base::FieldTrial::Probability kPrerenderControl1Probability = 100;
      const base::FieldTrial::Probability kPrerenderExp2Probability = 400;
      const base::FieldTrial::Probability kPrerenderControl2Probability = 100;

      scoped_refptr<base::FieldTrial> trial(
          new base::FieldTrial("Prefetch", kPrefetchDivisor,
                               "ContentPrefetchDisabled", 2011, 6, 30));

      const int kNoPrefetchGroup = trial->kDefaultGroupNumber;
      const int kYesPrefetchGroup =
          trial->AppendGroup("ContentPrefetchEnabled", kYesPrefetchProbability);
      const int kPrerenderExperiment1Group =
          trial->AppendGroup("ContentPrefetchPrerender1",
                             kPrerenderExp1Probability);
      const int kPrerenderControl1Group =
          trial->AppendGroup("ContentPrefetchPrerenderControl1",
                             kPrerenderControl1Probability);
      const int kPrerenderExperiment2Group =
          trial->AppendGroup("ContentPrefetchPrerender2",
                             kPrerenderExp2Probability);
      const int kPrerenderControl2Group =
          trial->AppendGroup("ContentPrefetchPrerenderControl2",
                             kPrerenderControl2Probability);
      const int trial_group = trial->group();
      if (trial_group == kYesPrefetchGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      } else if (trial_group == kNoPrefetchGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_DISABLED);
      } else if (trial_group == kPrerenderExperiment1Group ||
                 trial_group == kPrerenderExperiment2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP);
      } else if (trial_group == kPrerenderControl1Group ||
                 trial_group == kPrerenderControl2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP);
      } else {
        NOTREACHED();
      }
      break;
    }
    case PRERENDER_OPTION_DISABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(false);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    case PRERENDER_OPTION_ENABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
      break;
    case PRERENDER_OPTION_PREFETCH_ONLY:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    default:
      NOTREACHED();
  }

  UMA_HISTOGRAM_ENUMERATION("Prerender.Sessions",
                            PrerenderManager::GetMode(),
                            PrerenderManager::PRERENDER_MODE_MAX);
}

}  // namespace prerender
<|endoftext|>


<commit_before>// 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/shown_sections_handler.h"

#include <string>

#include "base/callback.h"
#include "base/command_line.h"
#include "base/string_number_conversions.h"
#include "base/values.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/pref_names.h"
#include "content/common/notification_details.h"
#include "content/common/notification_type.h"

namespace {

// Will cause an UMA notification if the mode of the new tab page
// was changed to hide/show the most visited thumbnails.
// TODO(aa): Needs to be updated to match newest NTP - http://crbug.com/57440
void NotifySectionDisabled(int new_mode, int old_mode, Profile *profile) {
  // If the oldmode HAD either thumbs or lists visible.
  bool old_had_it = (old_mode & THUMB) && !(old_mode & MENU_THUMB);
  bool new_has_it = (new_mode & THUMB) && !(new_mode & MENU_THUMB);

  if (old_had_it && !new_has_it) {
    UserMetrics::RecordAction(
        UserMetricsAction("ShowSections_RecentSitesDisabled"),
        profile);
  }

  if (new_has_it && !old_had_it) {
    UserMetrics::RecordAction(
        UserMetricsAction("ShowSections_RecentSitesEnabled"),
        profile);
  }
}

}  // namespace

// static
int ShownSectionsHandler::GetShownSections(PrefService* prefs) {
  return prefs->GetInteger(prefs::kNTPShownSections);
}

// static
void ShownSectionsHandler::SetShownSection(PrefService* prefs,
                                           Section section) {
  int shown_sections = GetShownSections(prefs);
  shown_sections &= ~ALL_SECTIONS_MASK;
  shown_sections |= section;
  prefs->SetInteger(prefs::kNTPShownSections, shown_sections);
}

ShownSectionsHandler::ShownSectionsHandler(PrefService* pref_service)
    : pref_service_(pref_service) {
  pref_registrar_.Init(pref_service);
  pref_registrar_.Add(prefs::kNTPShownSections, this);
}

void ShownSectionsHandler::RegisterMessages() {
  web_ui_->RegisterMessageCallback("getShownSections",
      NewCallback(this, &ShownSectionsHandler::HandleGetShownSections));
  web_ui_->RegisterMessageCallback("setShownSections",
      NewCallback(this, &ShownSectionsHandler::HandleSetShownSections));
}

void ShownSectionsHandler::Observe(NotificationType type,
                                   const NotificationSource& source,
                                   const NotificationDetails& details) {
  if (type == NotificationType::PREF_CHANGED) {
    std::string* pref_name = Details<std::string>(details).ptr();
    DCHECK(*pref_name == prefs::kNTPShownSections);
    int sections = pref_service_->GetInteger(prefs::kNTPShownSections);
    FundamentalValue sections_value(sections);
    web_ui_->CallJavascriptFunction("setShownSections", sections_value);
  } else {
    NOTREACHED();
  }
}

void ShownSectionsHandler::HandleGetShownSections(const ListValue* args) {
  int sections = GetShownSections(pref_service_);
  FundamentalValue sections_value(sections);
  web_ui_->CallJavascriptFunction("onShownSections", sections_value);
}

void ShownSectionsHandler::HandleSetShownSections(const ListValue* args) {
  double mode_double;
  CHECK(args->GetDouble(0, &mode_double));
  int mode = static_cast<int>(mode_double);
  int old_mode = pref_service_->GetInteger(prefs::kNTPShownSections);

  if (old_mode != mode) {
    NotifySectionDisabled(mode, old_mode, web_ui_->GetProfile());
    pref_service_->SetInteger(prefs::kNTPShownSections, mode);
  }
}

// static
void ShownSectionsHandler::RegisterUserPrefs(PrefService* pref_service) {
#if defined(OS_CHROMEOS)
  // Default to have expanded APPS and all other sections are minimized.
  pref_service->RegisterIntegerPref(prefs::kNTPShownSections,
                                    APPS | MENU_THUMB | MENU_RECENT);
#else
  pref_service->RegisterIntegerPref(prefs::kNTPShownSections, THUMB);
#endif
}

// static
void ShownSectionsHandler::MigrateUserPrefs(PrefService* pref_service,
                                            int old_pref_version,
                                            int new_pref_version) {
  // Nothing to migrate for default kNTPShownSections value.
  const PrefService::Preference* shown_sections_pref =
      pref_service->FindPreference(prefs::kNTPShownSections);
  if (shown_sections_pref->IsDefaultValue())
    return;

  bool changed = false;
  int shown_sections = pref_service->GetInteger(prefs::kNTPShownSections);

  if (old_pref_version < 3) {
    // In version 3, we went from being able to show multiple sections to being
    // able to show only one expanded at a time. The only two expandable
    // sections are APPS and THUMBS.
    if (shown_sections & APPS)
      shown_sections = APPS;
    else
      shown_sections = THUMB;

    changed = true;
  }

  if (changed)
    pref_service->SetInteger(prefs::kNTPShownSections, shown_sections);
}

// static
void ShownSectionsHandler::OnExtensionInstalled(PrefService* prefs,
                                                const Extension* extension) {
  if (extension->is_app()) {
    int mode = prefs->GetInteger(prefs::kNTPShownSections);

    // De-menu-mode the apps section.
    mode &= ~MENU_APPS;

    // Hide any open sections.
    mode &= ~ALL_SECTIONS_MASK;

    // Show the apps section.
    mode |= APPS;

    prefs->SetInteger(prefs::kNTPShownSections, mode);
  }
}
<commit_msg>Coverity: Check for a NULL preference.<commit_after>// 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/shown_sections_handler.h"

#include <string>

#include "base/callback.h"
#include "base/command_line.h"
#include "base/string_number_conversions.h"
#include "base/values.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/pref_names.h"
#include "content/common/notification_details.h"
#include "content/common/notification_type.h"

namespace {

// Will cause an UMA notification if the mode of the new tab page
// was changed to hide/show the most visited thumbnails.
// TODO(aa): Needs to be updated to match newest NTP - http://crbug.com/57440
void NotifySectionDisabled(int new_mode, int old_mode, Profile *profile) {
  // If the oldmode HAD either thumbs or lists visible.
  bool old_had_it = (old_mode & THUMB) && !(old_mode & MENU_THUMB);
  bool new_has_it = (new_mode & THUMB) && !(new_mode & MENU_THUMB);

  if (old_had_it && !new_has_it) {
    UserMetrics::RecordAction(
        UserMetricsAction("ShowSections_RecentSitesDisabled"),
        profile);
  }

  if (new_has_it && !old_had_it) {
    UserMetrics::RecordAction(
        UserMetricsAction("ShowSections_RecentSitesEnabled"),
        profile);
  }
}

}  // namespace

// static
int ShownSectionsHandler::GetShownSections(PrefService* prefs) {
  return prefs->GetInteger(prefs::kNTPShownSections);
}

// static
void ShownSectionsHandler::SetShownSection(PrefService* prefs,
                                           Section section) {
  int shown_sections = GetShownSections(prefs);
  shown_sections &= ~ALL_SECTIONS_MASK;
  shown_sections |= section;
  prefs->SetInteger(prefs::kNTPShownSections, shown_sections);
}

ShownSectionsHandler::ShownSectionsHandler(PrefService* pref_service)
    : pref_service_(pref_service) {
  pref_registrar_.Init(pref_service);
  pref_registrar_.Add(prefs::kNTPShownSections, this);
}

void ShownSectionsHandler::RegisterMessages() {
  web_ui_->RegisterMessageCallback("getShownSections",
      NewCallback(this, &ShownSectionsHandler::HandleGetShownSections));
  web_ui_->RegisterMessageCallback("setShownSections",
      NewCallback(this, &ShownSectionsHandler::HandleSetShownSections));
}

void ShownSectionsHandler::Observe(NotificationType type,
                                   const NotificationSource& source,
                                   const NotificationDetails& details) {
  if (type == NotificationType::PREF_CHANGED) {
    std::string* pref_name = Details<std::string>(details).ptr();
    DCHECK(*pref_name == prefs::kNTPShownSections);
    int sections = pref_service_->GetInteger(prefs::kNTPShownSections);
    FundamentalValue sections_value(sections);
    web_ui_->CallJavascriptFunction("setShownSections", sections_value);
  } else {
    NOTREACHED();
  }
}

void ShownSectionsHandler::HandleGetShownSections(const ListValue* args) {
  int sections = GetShownSections(pref_service_);
  FundamentalValue sections_value(sections);
  web_ui_->CallJavascriptFunction("onShownSections", sections_value);
}

void ShownSectionsHandler::HandleSetShownSections(const ListValue* args) {
  double mode_double;
  CHECK(args->GetDouble(0, &mode_double));
  int mode = static_cast<int>(mode_double);
  int old_mode = pref_service_->GetInteger(prefs::kNTPShownSections);

  if (old_mode != mode) {
    NotifySectionDisabled(mode, old_mode, web_ui_->GetProfile());
    pref_service_->SetInteger(prefs::kNTPShownSections, mode);
  }
}

// static
void ShownSectionsHandler::RegisterUserPrefs(PrefService* pref_service) {
#if defined(OS_CHROMEOS)
  // Default to have expanded APPS and all other sections are minimized.
  pref_service->RegisterIntegerPref(prefs::kNTPShownSections,
                                    APPS | MENU_THUMB | MENU_RECENT);
#else
  pref_service->RegisterIntegerPref(prefs::kNTPShownSections, THUMB);
#endif
}

// static
void ShownSectionsHandler::MigrateUserPrefs(PrefService* pref_service,
                                            int old_pref_version,
                                            int new_pref_version) {
  // Nothing to migrate for default kNTPShownSections value.
  const PrefService::Preference* shown_sections_pref =
      pref_service->FindPreference(prefs::kNTPShownSections);
  if (!shown_sections_pref || shown_sections_pref->IsDefaultValue())
    return;

  bool changed = false;
  int shown_sections = pref_service->GetInteger(prefs::kNTPShownSections);

  if (old_pref_version < 3) {
    // In version 3, we went from being able to show multiple sections to being
    // able to show only one expanded at a time. The only two expandable
    // sections are APPS and THUMBS.
    if (shown_sections & APPS)
      shown_sections = APPS;
    else
      shown_sections = THUMB;

    changed = true;
  }

  if (changed)
    pref_service->SetInteger(prefs::kNTPShownSections, shown_sections);
}

// static
void ShownSectionsHandler::OnExtensionInstalled(PrefService* prefs,
                                                const Extension* extension) {
  if (extension->is_app()) {
    int mode = prefs->GetInteger(prefs::kNTPShownSections);

    // De-menu-mode the apps section.
    mode &= ~MENU_APPS;

    // Hide any open sections.
    mode &= ~ALL_SECTIONS_MASK;

    // Show the apps section.
    mode |= APPS;

    prefs->SetInteger(prefs::kNTPShownSections, mode);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 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/views/browser_actions_container.h"

#include "app/gfx/canvas.h"
#include "app/resource_bundle.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/extensions/extension_popup.h"
#include "chrome/browser/views/toolbar_view.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "grit/app_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "views/controls/button/text_button.h"

// The size (both dimensions) of the buttons for page actions.
static const int kButtonSize = 29;

// The padding between the browser actions and the omnibox/page menu.
static const int kHorizontalPadding = 4;

// The padding between browser action buttons. Visually, the actual number of
// empty (non-drawing) pixels is this value + 2 when adjacent browser icons
// use their maximum allowed size.
static const int kBrowserActionButtonPadding = 3;

// This is the same value from toolbar.cc. We position the browser actions
// container flush with the edges of the toolbar as a special case so that we
// can draw the badge outside the visual bounds of the container.
static const int kControlVertOffset = 6;

// The maximum of the minimum number of browser actions present when there is
// not enough space to fit all the browser actions in the toolbar.
static const int kMinimumNumberOfVisibleBrowserActions = 2;

////////////////////////////////////////////////////////////////////////////////
// BrowserActionButton

BrowserActionButton::BrowserActionButton(Extension* extension,
                                         BrowserActionsContainer* panel)
    : MenuButton(this, L"", NULL, false),
      browser_action_(extension->browser_action()),
      extension_(extension),
      tracker_(NULL),
      panel_(panel) {
  set_alignment(TextButton::ALIGN_CENTER);

  // No UpdateState() here because View heirarchy not setup yet. Our parent
  // should call UpdateState() after creation.

  registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
                 Source<ExtensionAction>(browser_action_));
}

BrowserActionButton::~BrowserActionButton() {
  if (tracker_) {
    tracker_->StopTrackingImageLoad();
    tracker_ = NULL;  // The tracker object will be deleted when we return.
  }
}

gfx::Insets BrowserActionButton::GetInsets() const {
  static gfx::Insets zero_inset;
  return zero_inset;
}

void BrowserActionButton::ButtonPressed(
    views::Button* sender, const views::Event& event) {
  panel_->OnBrowserActionExecuted(this);
}

void BrowserActionButton::LoadImage() {
  // Load the default image from the browser action asynchronously on the file
  // thread. We'll get a call back into OnImageLoaded if the image loads
  // successfully.
  std::string relative_path = browser_action()->default_icon_path();
  if (relative_path.empty())
    return;

  tracker_ = new ImageLoadingTracker(this, 1);
  tracker_->PostLoadImageTask(
      extension()->GetResource(relative_path),
      gfx::Size(Extension::kBrowserActionIconMaxSize,
                Extension::kBrowserActionIconMaxSize));
}

void BrowserActionButton::OnImageLoaded(SkBitmap* image, size_t index) {
  if (image)
    SetIcon(*image);
  tracker_ = NULL;  // The tracker object will delete itself when we return.
  GetParent()->SchedulePaint();
}

void BrowserActionButton::UpdateState() {
  int tab_id = panel_->GetCurrentTabId();
  if (tab_id < 0)
    return;

  SkBitmap image = browser_action()->GetIcon(tab_id);
  if (image.isNull())
    LoadImage();
  else
    SetIcon(image);

  SetTooltipText(ASCIIToWide(browser_action()->GetTitle(tab_id)));
  GetParent()->SchedulePaint();
}

void BrowserActionButton::Observe(NotificationType type,
                                  const NotificationSource& source,
                                  const NotificationDetails& details) {
  if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED) {
    UpdateState();
  } else {
    NOTREACHED() << L"Received unexpected notification";
  }
}

bool BrowserActionButton::IsPopup() {
  return browser_action_->has_popup();
}

bool BrowserActionButton::Activate() {
  if (IsPopup()) {
    panel_->OnBrowserActionExecuted(this);

    // TODO(erikkay): Run a nested modal loop while the mouse is down to
    // enable menu-like drag-select behavior.

    // The return value of this method is returned via OnMousePressed.
    // We need to return false here since we're handing off focus to another
    // widget/view, and true will grab it right back and try to send events
    // to us.
    return false;
  }
  return true;
}

bool BrowserActionButton::OnMousePressed(const views::MouseEvent& e) {
  if (IsPopup())
    return MenuButton::OnMousePressed(e);
  return TextButton::OnMousePressed(e);
}

void BrowserActionButton::OnMouseReleased(const views::MouseEvent& e,
                                          bool canceled) {
  if (IsPopup()) {
    // TODO(erikkay) this never actually gets called (probably because of the
    // loss of focus).
    MenuButton::OnMouseReleased(e, canceled);
  } else {
    TextButton::OnMouseReleased(e, canceled);
  }
}

bool BrowserActionButton::OnKeyReleased(const views::KeyEvent& e) {
  if (IsPopup())
    return MenuButton::OnKeyReleased(e);
  return TextButton::OnKeyReleased(e);
}

void BrowserActionButton::OnMouseExited(const views::MouseEvent& e) {
  if (IsPopup())
    MenuButton::OnMouseExited(e);
  else
    TextButton::OnMouseExited(e);
}

void BrowserActionButton::PopupDidShow() {
  SetState(views::CustomButton::BS_PUSHED);
  menu_visible_ = true;
}

void BrowserActionButton::PopupDidHide() {
  SetState(views::CustomButton::BS_NORMAL);
  menu_visible_ = false;
}

////////////////////////////////////////////////////////////////////////////////
// BrowserActionView

BrowserActionView::BrowserActionView(Extension* extension,
                                     BrowserActionsContainer* panel)
    : panel_(panel) {
  button_ = new BrowserActionButton(extension, panel);
  AddChildView(button_);
  button_->UpdateState();
}

void BrowserActionView::Layout() {
  button_->SetBounds(0, kControlVertOffset, width(), kButtonSize);
}

void BrowserActionView::PaintChildren(gfx::Canvas* canvas) {
  View::PaintChildren(canvas);
  ExtensionAction* action = button()->browser_action();
  int tab_id = panel_->GetCurrentTabId();
  if (tab_id < 0)
    return;

  action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id);
}

////////////////////////////////////////////////////////////////////////////////
// BrowserActionsContainer

BrowserActionsContainer::BrowserActionsContainer(
    Profile* profile, ToolbarView* toolbar)
    : profile_(profile),
      toolbar_(toolbar),
      popup_(NULL),
      popup_button_(NULL),
      ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
  ExtensionsService* extension_service = profile->GetExtensionsService();
  if (!extension_service)  // The |extension_service| can be NULL in Incognito.
    return;

  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
                 Source<ExtensionsService>(extension_service));
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 Source<ExtensionsService>(extension_service));
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
                 Source<ExtensionsService>(extension_service));
  registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
                 Source<Profile>(profile_));

  for (size_t i = 0; i < extension_service->extensions()->size(); ++i)
    AddBrowserAction(extension_service->extensions()->at(i));

  SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR);
}

BrowserActionsContainer::~BrowserActionsContainer() {
  HidePopup();
  DeleteBrowserActionViews();
}

int BrowserActionsContainer::GetCurrentTabId() {
  TabContents* tab_contents = toolbar_->browser()->GetSelectedTabContents();
  if (!tab_contents)
    return -1;

  return tab_contents->controller().session_id().id();
}

void BrowserActionsContainer::RefreshBrowserActionViews() {
  for (size_t i = 0; i < browser_action_views_.size(); ++i)
    browser_action_views_[i]->button()->UpdateState();
}

void BrowserActionsContainer::AddBrowserAction(Extension* extension) {
#if defined(DEBUG)
  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
    DCHECK(browser_action_views_[i]->button()->extension() != extension) <<
           "Asked to add a browser action view for an extension that already "
           "exists.";
  }
#endif
  if (!extension->browser_action())
    return;

  BrowserActionView* view = new BrowserActionView(extension, this);
  browser_action_views_.push_back(view);
  AddChildView(view);
}

void BrowserActionsContainer::RemoveBrowserAction(Extension* extension) {
  if (!extension->browser_action())
    return;

  for (std::vector<BrowserActionView*>::iterator iter =
       browser_action_views_.begin(); iter != browser_action_views_.end();
       ++iter) {
    if ((*iter)->button()->extension() == extension) {
      RemoveChildView(*iter);
      browser_action_views_.erase(iter);
      return;
    }
  }

   NOTREACHED() << "Asked to remove a browser action view that doesn't exist.";
}

void BrowserActionsContainer::DeleteBrowserActionViews() {
  if (!browser_action_views_.empty()) {
    for (size_t i = 0; i < browser_action_views_.size(); ++i)
      RemoveChildView(browser_action_views_[i]);
    STLDeleteContainerPointers(browser_action_views_.begin(),
                               browser_action_views_.end());
    browser_action_views_.clear();
  }
}

void BrowserActionsContainer::OnBrowserActionVisibilityChanged() {
  toolbar_->Layout();
}

void BrowserActionsContainer::HidePopup() {
  if (popup_) {
    // This sometimes gets called via a timer (See BubbleLostFocus), so clear
    // the task factory. in case one is pending.
    task_factory_.RevokeAll();

    // Save these variables in local temporaries since destroying the popup
    // calls BubbleLostFocus to be called, which will try to call HidePopup()
    // again if popup_ is non-null.
    ExtensionPopup* closing_popup = popup_;
    BrowserActionButton* closing_button = popup_button_;
    popup_ = NULL;
    popup_button_ = NULL;

    closing_popup->DetachFromBrowser();
    delete closing_popup;
    closing_button->PopupDidHide();
    return;
  }
}

void BrowserActionsContainer::TestExecuteBrowserAction(int index) {
  BrowserActionButton* button = browser_action_views_[index]->button();
  OnBrowserActionExecuted(button);
}

void BrowserActionsContainer::OnBrowserActionExecuted(
    BrowserActionButton* button) {
  ExtensionAction* browser_action = button->browser_action();

  // Popups just display.  No notification to the extension.
  // TODO(erikkay): should there be?
  if (button->IsPopup()) {
    // If we're showing the same popup, just hide it and return.
    bool same_showing = popup_ && button == popup_button_;

    // Always hide the current popup, even if it's not the same.
    // Only one popup should be visible at a time.
    HidePopup();

    if (same_showing)
      return;

    gfx::Point origin;
    View::ConvertPointToScreen(button, &origin);
    gfx::Rect rect = button->bounds();
    rect.set_x(origin.x());
    rect.set_y(origin.y());
    popup_ = ExtensionPopup::Show(browser_action->popup_url(),
                                  toolbar_->browser(),
                                  rect);
    popup_->set_delegate(this);
    popup_button_ = button;
    popup_button_->PopupDidShow();
    return;
  }

  // Otherwise, we send the action to the extension.
  ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
      profile_, browser_action->extension_id(), toolbar_->browser());
}

gfx::Size BrowserActionsContainer::GetPreferredSize() {
  if (browser_action_views_.empty())
    return gfx::Size(0, 0);
  int width = kHorizontalPadding * 2 +
      browser_action_views_.size() * kButtonSize;
  if (browser_action_views_.size() > 1)
    width += (browser_action_views_.size() - 1) * kBrowserActionButtonPadding;
  return gfx::Size(width, kButtonSize);
}

void BrowserActionsContainer::Layout() {
  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
    BrowserActionView* view = browser_action_views_[i];
    int x = kHorizontalPadding +
        i * (kButtonSize + kBrowserActionButtonPadding);
    if (x + kButtonSize <= width()) {
      view->SetBounds(x, 0, kButtonSize, height());
      view->SetVisible(true);
    } else {
      view->SetVisible(false);
    }
  }
}

void BrowserActionsContainer::Observe(NotificationType type,
                                      const NotificationSource& source,
                                      const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSION_LOADED:
      AddBrowserAction(Details<Extension>(details).ptr());
      OnBrowserActionVisibilityChanged();
      break;

    case NotificationType::EXTENSION_UNLOADED:
    case NotificationType::EXTENSION_UNLOADED_DISABLED:
      RemoveBrowserAction(Details<Extension>(details).ptr());
      OnBrowserActionVisibilityChanged();
      break;

    case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE:
      if (Details<ExtensionHost>(popup_->host()) != details)
        return;

      HidePopup();

    default:
      NOTREACHED() << L"Unexpected notification";
  }
}

void BrowserActionsContainer::BubbleBrowserWindowMoved(BrowserBubble* bubble) {
}

void BrowserActionsContainer::BubbleBrowserWindowClosing(
    BrowserBubble* bubble) {
  HidePopup();
}

void BrowserActionsContainer::BubbleGotFocus(BrowserBubble* bubble) {
}

void BrowserActionsContainer::BubbleLostFocus(BrowserBubble* bubble) {
  if (!popup_)
    return;

  // This is a bit annoying.  If you click on the button that generated the
  // current popup, then we first get this lost focus message, and then
  // we get the click action.  This results in the popup being immediately
  // shown again.  To workaround this, we put in a delay.
  MessageLoop::current()->PostTask(FROM_HERE,
      task_factory_.NewRunnableMethod(&BrowserActionsContainer::HidePopup));
}

int BrowserActionsContainer::GetClippedPreferredWidth(int available_width) {
  if (browser_action_views_.size() == 0)
    return 0;

  // We have at least one browser action. Make some of them sticky.
  int min_width = kHorizontalPadding * 2 +
      std::min(static_cast<int>(browser_action_views_.size()),
               kMinimumNumberOfVisibleBrowserActions) * kButtonSize;

  // Even if available_width is <= 0, we still return at least the |min_width|.
  if (available_width <= 0)
    return min_width;

  return std::max(min_width, available_width - available_width % kButtonSize +
                  kHorizontalPadding * 2);
}
<commit_msg>Fix paint glitch on load/unload browser action.<commit_after>// Copyright (c) 2009 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/views/browser_actions_container.h"

#include "app/gfx/canvas.h"
#include "app/resource_bundle.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/extensions/extension_popup.h"
#include "chrome/browser/views/toolbar_view.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "grit/app_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "views/controls/button/text_button.h"

// The size (both dimensions) of the buttons for page actions.
static const int kButtonSize = 29;

// The padding between the browser actions and the omnibox/page menu.
static const int kHorizontalPadding = 4;

// The padding between browser action buttons. Visually, the actual number of
// empty (non-drawing) pixels is this value + 2 when adjacent browser icons
// use their maximum allowed size.
static const int kBrowserActionButtonPadding = 3;

// This is the same value from toolbar.cc. We position the browser actions
// container flush with the edges of the toolbar as a special case so that we
// can draw the badge outside the visual bounds of the container.
static const int kControlVertOffset = 6;

// The maximum of the minimum number of browser actions present when there is
// not enough space to fit all the browser actions in the toolbar.
static const int kMinimumNumberOfVisibleBrowserActions = 2;

////////////////////////////////////////////////////////////////////////////////
// BrowserActionButton

BrowserActionButton::BrowserActionButton(Extension* extension,
                                         BrowserActionsContainer* panel)
    : MenuButton(this, L"", NULL, false),
      browser_action_(extension->browser_action()),
      extension_(extension),
      tracker_(NULL),
      panel_(panel) {
  set_alignment(TextButton::ALIGN_CENTER);

  // No UpdateState() here because View heirarchy not setup yet. Our parent
  // should call UpdateState() after creation.

  registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
                 Source<ExtensionAction>(browser_action_));
}

BrowserActionButton::~BrowserActionButton() {
  if (tracker_) {
    tracker_->StopTrackingImageLoad();
    tracker_ = NULL;  // The tracker object will be deleted when we return.
  }
}

gfx::Insets BrowserActionButton::GetInsets() const {
  static gfx::Insets zero_inset;
  return zero_inset;
}

void BrowserActionButton::ButtonPressed(
    views::Button* sender, const views::Event& event) {
  panel_->OnBrowserActionExecuted(this);
}

void BrowserActionButton::LoadImage() {
  // Load the default image from the browser action asynchronously on the file
  // thread. We'll get a call back into OnImageLoaded if the image loads
  // successfully.
  std::string relative_path = browser_action()->default_icon_path();
  if (relative_path.empty())
    return;

  tracker_ = new ImageLoadingTracker(this, 1);
  tracker_->PostLoadImageTask(
      extension()->GetResource(relative_path),
      gfx::Size(Extension::kBrowserActionIconMaxSize,
                Extension::kBrowserActionIconMaxSize));
}

void BrowserActionButton::OnImageLoaded(SkBitmap* image, size_t index) {
  if (image)
    SetIcon(*image);
  tracker_ = NULL;  // The tracker object will delete itself when we return.
  GetParent()->SchedulePaint();
}

void BrowserActionButton::UpdateState() {
  int tab_id = panel_->GetCurrentTabId();
  if (tab_id < 0)
    return;

  SkBitmap image = browser_action()->GetIcon(tab_id);
  if (image.isNull())
    LoadImage();
  else
    SetIcon(image);

  SetTooltipText(ASCIIToWide(browser_action()->GetTitle(tab_id)));
  GetParent()->SchedulePaint();
}

void BrowserActionButton::Observe(NotificationType type,
                                  const NotificationSource& source,
                                  const NotificationDetails& details) {
  if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED) {
    UpdateState();
  } else {
    NOTREACHED() << L"Received unexpected notification";
  }
}

bool BrowserActionButton::IsPopup() {
  return browser_action_->has_popup();
}

bool BrowserActionButton::Activate() {
  if (IsPopup()) {
    panel_->OnBrowserActionExecuted(this);

    // TODO(erikkay): Run a nested modal loop while the mouse is down to
    // enable menu-like drag-select behavior.

    // The return value of this method is returned via OnMousePressed.
    // We need to return false here since we're handing off focus to another
    // widget/view, and true will grab it right back and try to send events
    // to us.
    return false;
  }
  return true;
}

bool BrowserActionButton::OnMousePressed(const views::MouseEvent& e) {
  if (IsPopup())
    return MenuButton::OnMousePressed(e);
  return TextButton::OnMousePressed(e);
}

void BrowserActionButton::OnMouseReleased(const views::MouseEvent& e,
                                          bool canceled) {
  if (IsPopup()) {
    // TODO(erikkay) this never actually gets called (probably because of the
    // loss of focus).
    MenuButton::OnMouseReleased(e, canceled);
  } else {
    TextButton::OnMouseReleased(e, canceled);
  }
}

bool BrowserActionButton::OnKeyReleased(const views::KeyEvent& e) {
  if (IsPopup())
    return MenuButton::OnKeyReleased(e);
  return TextButton::OnKeyReleased(e);
}

void BrowserActionButton::OnMouseExited(const views::MouseEvent& e) {
  if (IsPopup())
    MenuButton::OnMouseExited(e);
  else
    TextButton::OnMouseExited(e);
}

void BrowserActionButton::PopupDidShow() {
  SetState(views::CustomButton::BS_PUSHED);
  menu_visible_ = true;
}

void BrowserActionButton::PopupDidHide() {
  SetState(views::CustomButton::BS_NORMAL);
  menu_visible_ = false;
}

////////////////////////////////////////////////////////////////////////////////
// BrowserActionView

BrowserActionView::BrowserActionView(Extension* extension,
                                     BrowserActionsContainer* panel)
    : panel_(panel) {
  button_ = new BrowserActionButton(extension, panel);
  AddChildView(button_);
  button_->UpdateState();
}

void BrowserActionView::Layout() {
  button_->SetBounds(0, kControlVertOffset, width(), kButtonSize);
}

void BrowserActionView::PaintChildren(gfx::Canvas* canvas) {
  View::PaintChildren(canvas);
  ExtensionAction* action = button()->browser_action();
  int tab_id = panel_->GetCurrentTabId();
  if (tab_id < 0)
    return;

  action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id);
}

////////////////////////////////////////////////////////////////////////////////
// BrowserActionsContainer

BrowserActionsContainer::BrowserActionsContainer(
    Profile* profile, ToolbarView* toolbar)
    : profile_(profile),
      toolbar_(toolbar),
      popup_(NULL),
      popup_button_(NULL),
      ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
  ExtensionsService* extension_service = profile->GetExtensionsService();
  if (!extension_service)  // The |extension_service| can be NULL in Incognito.
    return;

  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
                 Source<ExtensionsService>(extension_service));
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 Source<ExtensionsService>(extension_service));
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
                 Source<ExtensionsService>(extension_service));
  registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
                 Source<Profile>(profile_));

  for (size_t i = 0; i < extension_service->extensions()->size(); ++i)
    AddBrowserAction(extension_service->extensions()->at(i));

  SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR);
}

BrowserActionsContainer::~BrowserActionsContainer() {
  HidePopup();
  DeleteBrowserActionViews();
}

int BrowserActionsContainer::GetCurrentTabId() {
  TabContents* tab_contents = toolbar_->browser()->GetSelectedTabContents();
  if (!tab_contents)
    return -1;

  return tab_contents->controller().session_id().id();
}

void BrowserActionsContainer::RefreshBrowserActionViews() {
  for (size_t i = 0; i < browser_action_views_.size(); ++i)
    browser_action_views_[i]->button()->UpdateState();
}

void BrowserActionsContainer::AddBrowserAction(Extension* extension) {
#if defined(DEBUG)
  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
    DCHECK(browser_action_views_[i]->button()->extension() != extension) <<
           "Asked to add a browser action view for an extension that already "
           "exists.";
  }
#endif
  if (!extension->browser_action())
    return;

  BrowserActionView* view = new BrowserActionView(extension, this);
  browser_action_views_.push_back(view);
  AddChildView(view);
  if (GetParent())
    GetParent()->SchedulePaint();
}

void BrowserActionsContainer::RemoveBrowserAction(Extension* extension) {
  if (!extension->browser_action())
    return;

  for (std::vector<BrowserActionView*>::iterator iter =
       browser_action_views_.begin(); iter != browser_action_views_.end();
       ++iter) {
    if ((*iter)->button()->extension() == extension) {
      RemoveChildView(*iter);
      browser_action_views_.erase(iter);
      if (GetParent())
        GetParent()->SchedulePaint();
      return;
    }
  }

  NOTREACHED() << "Asked to remove a browser action view that doesn't exist.";
}

void BrowserActionsContainer::DeleteBrowserActionViews() {
  if (!browser_action_views_.empty()) {
    for (size_t i = 0; i < browser_action_views_.size(); ++i)
      RemoveChildView(browser_action_views_[i]);
    STLDeleteContainerPointers(browser_action_views_.begin(),
                               browser_action_views_.end());
    browser_action_views_.clear();
  }
}

void BrowserActionsContainer::OnBrowserActionVisibilityChanged() {
  toolbar_->Layout();
}

void BrowserActionsContainer::HidePopup() {
  if (popup_) {
    // This sometimes gets called via a timer (See BubbleLostFocus), so clear
    // the task factory. in case one is pending.
    task_factory_.RevokeAll();

    // Save these variables in local temporaries since destroying the popup
    // calls BubbleLostFocus to be called, which will try to call HidePopup()
    // again if popup_ is non-null.
    ExtensionPopup* closing_popup = popup_;
    BrowserActionButton* closing_button = popup_button_;
    popup_ = NULL;
    popup_button_ = NULL;

    closing_popup->DetachFromBrowser();
    delete closing_popup;
    closing_button->PopupDidHide();
    return;
  }
}

void BrowserActionsContainer::TestExecuteBrowserAction(int index) {
  BrowserActionButton* button = browser_action_views_[index]->button();
  OnBrowserActionExecuted(button);
}

void BrowserActionsContainer::OnBrowserActionExecuted(
    BrowserActionButton* button) {
  ExtensionAction* browser_action = button->browser_action();

  // Popups just display.  No notification to the extension.
  // TODO(erikkay): should there be?
  if (button->IsPopup()) {
    // If we're showing the same popup, just hide it and return.
    bool same_showing = popup_ && button == popup_button_;

    // Always hide the current popup, even if it's not the same.
    // Only one popup should be visible at a time.
    HidePopup();

    if (same_showing)
      return;

    gfx::Point origin;
    View::ConvertPointToScreen(button, &origin);
    gfx::Rect rect = button->bounds();
    rect.set_x(origin.x());
    rect.set_y(origin.y());
    popup_ = ExtensionPopup::Show(browser_action->popup_url(),
                                  toolbar_->browser(),
                                  rect);
    popup_->set_delegate(this);
    popup_button_ = button;
    popup_button_->PopupDidShow();
    return;
  }

  // Otherwise, we send the action to the extension.
  ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
      profile_, browser_action->extension_id(), toolbar_->browser());
}

gfx::Size BrowserActionsContainer::GetPreferredSize() {
  if (browser_action_views_.empty())
    return gfx::Size(0, 0);
  int width = kHorizontalPadding * 2 +
      browser_action_views_.size() * kButtonSize;
  if (browser_action_views_.size() > 1)
    width += (browser_action_views_.size() - 1) * kBrowserActionButtonPadding;
  return gfx::Size(width, kButtonSize);
}

void BrowserActionsContainer::Layout() {
  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
    BrowserActionView* view = browser_action_views_[i];
    int x = kHorizontalPadding +
        i * (kButtonSize + kBrowserActionButtonPadding);
    if (x + kButtonSize <= width()) {
      view->SetBounds(x, 0, kButtonSize, height());
      view->SetVisible(true);
    } else {
      view->SetVisible(false);
    }
  }
}

void BrowserActionsContainer::Observe(NotificationType type,
                                      const NotificationSource& source,
                                      const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSION_LOADED:
      AddBrowserAction(Details<Extension>(details).ptr());
      OnBrowserActionVisibilityChanged();
      break;

    case NotificationType::EXTENSION_UNLOADED:
    case NotificationType::EXTENSION_UNLOADED_DISABLED:
      RemoveBrowserAction(Details<Extension>(details).ptr());
      OnBrowserActionVisibilityChanged();
      break;

    case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE:
      if (Details<ExtensionHost>(popup_->host()) != details)
        return;

      HidePopup();

    default:
      NOTREACHED() << L"Unexpected notification";
  }
}

void BrowserActionsContainer::BubbleBrowserWindowMoved(BrowserBubble* bubble) {
}

void BrowserActionsContainer::BubbleBrowserWindowClosing(
    BrowserBubble* bubble) {
  HidePopup();
}

void BrowserActionsContainer::BubbleGotFocus(BrowserBubble* bubble) {
}

void BrowserActionsContainer::BubbleLostFocus(BrowserBubble* bubble) {
  if (!popup_)
    return;

  // This is a bit annoying.  If you click on the button that generated the
  // current popup, then we first get this lost focus message, and then
  // we get the click action.  This results in the popup being immediately
  // shown again.  To workaround this, we put in a delay.
  MessageLoop::current()->PostTask(FROM_HERE,
      task_factory_.NewRunnableMethod(&BrowserActionsContainer::HidePopup));
}

int BrowserActionsContainer::GetClippedPreferredWidth(int available_width) {
  if (browser_action_views_.size() == 0)
    return 0;

  // We have at least one browser action. Make some of them sticky.
  int min_width = kHorizontalPadding * 2 +
      std::min(static_cast<int>(browser_action_views_.size()),
               kMinimumNumberOfVisibleBrowserActions) * kButtonSize;

  // Even if available_width is <= 0, we still return at least the |min_width|.
  if (available_width <= 0)
    return min_width;

  return std::max(min_width, available_width - available_width % kButtonSize +
                  kHorizontalPadding * 2);
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 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/worker_host/worker_process_host.h"

#include <set>

#include "base/command_line.h"
#include "base/debug_util.h"
#if defined(OS_POSIX)
#include "base/global_descriptors_posix.h"
#endif
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/worker_host/message_port_dispatcher.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/debug_flags.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/result_codes.h"
#include "chrome/common/worker_messages.h"
#include "ipc/ipc_descriptors.h"
#include "ipc/ipc_switches.h"
#include "net/base/registry_controlled_domain.h"

#if defined(OS_WIN)
#include "chrome/browser/sandbox_policy.h"
#endif

// Notifies RenderViewHost that one or more worker objects crashed.
class WorkerCrashTask : public Task {
 public:
  WorkerCrashTask(int render_process_id, int render_view_id)
      : render_process_id_(render_process_id),
        render_view_id_(render_view_id) { }

  void Run() {
    RenderViewHost* host =
        RenderViewHost::FromID(render_process_id_, render_view_id_);
    if (host) {
      RenderViewHostDelegate::BrowserIntegration* integration_delegate =
          host->delegate()->GetBrowserIntegrationDelegate();
      if (integration_delegate)
        integration_delegate->OnCrashedWorker();
    }
  }

 private:
  int render_process_id_;
  int render_view_id_;
};

WorkerProcessHost::WorkerProcessHost(
    ResourceDispatcherHost* resource_dispatcher_host_)
    : ChildProcessHost(WORKER_PROCESS, resource_dispatcher_host_) {
  next_route_id_callback_.reset(NewCallbackWithReturnValue(
      WorkerService::GetInstance(), &WorkerService::next_worker_route_id));
}

WorkerProcessHost::~WorkerProcessHost() {
  // Let interested observers know we are being deleted.
  NotificationService::current()->Notify(
      NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
      Source<WorkerProcessHost>(this),
      NotificationService::NoDetails());

  // If we crashed, tell the RenderViewHost.
  MessageLoop* ui_loop = WorkerService::GetInstance()->ui_loop();
  for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
    ui_loop->PostTask(FROM_HERE, new WorkerCrashTask(
        i->renderer_process_id, i->render_view_route_id));
  }

  ChildProcessSecurityPolicy::GetInstance()->Remove(GetProcessId());
}

bool WorkerProcessHost::Init() {
  if (!CreateChannel())
    return false;

  std::wstring exe_path;
  if (!PathService::Get(base::FILE_EXE, &exe_path))
    return false;

  CommandLine cmd_line(exe_path);
  cmd_line.AppendSwitchWithValue(switches::kProcessType,
                                 switches::kWorkerProcess);
  cmd_line.AppendSwitchWithValue(switches::kProcessChannelID,
                                 ASCIIToWide(channel_id()));

  if (CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableNativeWebWorkers)) {
    cmd_line.AppendSwitch(switches::kEnableNativeWebWorkers);
  }

  if (CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kWebWorkerShareProcesses)) {
    cmd_line.AppendSwitch(switches::kWebWorkerShareProcesses);
  }

  base::ProcessHandle process;
#if defined(OS_WIN)
  process = sandbox::StartProcess(&cmd_line);
#else
  // This code is duplicated with browser_render_process_host.cc, but
  // there's not a good place to de-duplicate it.
  base::file_handle_mapping_vector fds_to_map;
  const int ipcfd = channel().GetClientFileDescriptor();
  if (ipcfd > -1) {
    fds_to_map.push_back(std::pair<int, int>(
        ipcfd, kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
  }
  base::LaunchApp(cmd_line.argv(), fds_to_map, false, &process);
#endif
  if (!process)
    return false;
  SetHandle(process);

  ChildProcessSecurityPolicy::GetInstance()->Add(GetProcessId());

  return true;
}

void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
  ChildProcessSecurityPolicy::GetInstance()->GrantRequestURL(
      GetProcessId(), instance.url);

  instances_.push_back(instance);
  Send(new WorkerProcessMsg_CreateWorker(
      instance.url, instance.worker_route_id));

  UpdateTitle();
  instances_.back().sender->Send(
      new ViewMsg_DedicatedWorkerCreated(instance.sender_route_id));
}

bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
                                      int sender_pid) {
  for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
    if (i->sender_pid == sender_pid &&
        i->sender_route_id == message.routing_id()) {
      RelayMessage(
          message, this, i->worker_route_id, next_route_id_callback_.get());
      return true;
    }
  }

  return false;
}

URLRequestContext* WorkerProcessHost::GetRequestContext(
    uint32 request_id,
    const ViewHostMsg_Resource_Request& request_data) {
  return NULL;
}

void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
  bool msg_is_ok = true;
  bool handled = MessagePortDispatcher::GetInstance()->OnMessageReceived(
      message, this, next_route_id_callback_.get(), &msg_is_ok);

  if (!handled) {
    handled = true;
    IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok)
      IPC_MESSAGE_HANDLER(ViewHostMsg_CreateDedicatedWorker,
                          OnCreateDedicatedWorker)
      IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker,
                          OnCancelCreateDedicatedWorker)
      IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker,
                          OnForwardToWorker)
      IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP_EX()
  }

  if (!msg_is_ok) {
    NOTREACHED();
    base::KillProcess(handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
  }

  if (handled)
    return;

  for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
    if (i->worker_route_id == message.routing_id()) {
      CallbackWithReturnValue<int>::Type* next_route_id =
          GetNextRouteIdCallback(i->sender);
      RelayMessage(message, i->sender, i->sender_route_id, next_route_id);

      if (message.type() == WorkerHostMsg_WorkerContextDestroyed::ID) {
        instances_.erase(i);
        UpdateTitle();
      }
      break;
    }
  }
}

CallbackWithReturnValue<int>::Type* WorkerProcessHost::GetNextRouteIdCallback(
    IPC::Message::Sender* sender) {
  // We don't keep callbacks for senders associated with workers, so figure out
  // what kind of sender this is, and cast it to the correct class to get the
  // callback.
  for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
       !iter.Done(); ++iter) {
    WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
    if (static_cast<IPC::Message::Sender*>(worker) == sender)
      return worker->next_route_id_callback_.get();
  }

  // Must be a ResourceMessageFilter.
  return static_cast<ResourceMessageFilter*>(sender)->next_route_id_callback();
}

void WorkerProcessHost::RelayMessage(
    const IPC::Message& message,
    IPC::Message::Sender* sender,
    int route_id,
    CallbackWithReturnValue<int>::Type* next_route_id) {
  IPC::Message* new_message;
  if (message.type() == WorkerMsg_PostMessage::ID) {
    // We want to send the receiver a routing id for the new channel, so
    // crack the message first.
    string16 msg;
    int sent_message_port_id;
    int new_routing_id;  // Ignore the bogus value from the sender.
    if (!WorkerMsg_PostMessage::Read(
            &message, &msg, &sent_message_port_id, &new_routing_id)) {
      return;
    }

    if (sent_message_port_id != MSG_ROUTING_NONE) {
      new_routing_id = next_route_id->Run();
      MessagePortDispatcher::GetInstance()->UpdateMessagePort(
          sent_message_port_id, sender, new_routing_id, next_route_id);
    }

    new_message = new WorkerMsg_PostMessage(
        route_id, msg, sent_message_port_id, new_routing_id);
  } else {
    new_message = new IPC::Message(message);
    new_message->set_routing_id(route_id);
  }

  sender->Send(new_message);
}

void WorkerProcessHost::SenderShutdown(IPC::Message::Sender* sender) {
  for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
    if (i->sender == sender) {
      Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id));
      i = instances_.erase(i);
    } else {
      ++i;
    }
  }
}

void WorkerProcessHost::UpdateTitle() {
  std::set<std::string> titles;
  for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
    std::string title =
        net::RegistryControlledDomainService::GetDomainAndRegistry(i->url);
    // Use the host name if the domain is empty, i.e. localhost or IP address.
    if (title.empty())
      title = i->url.host();
    // If the host name is empty, i.e. file url, use the path.
    if (title.empty())
      title = i->url.path();
    titles.insert(title);
  }

  std::string display_title;
  for (std::set<std::string>::iterator i = titles.begin();
       i != titles.end(); ++i) {
    if (!display_title.empty())
      display_title += ", ";
    display_title += *i;
  }

  set_name(ASCIIToWide(display_title));
}

void WorkerProcessHost::OnCreateDedicatedWorker(const GURL& url,
                                                int render_view_route_id,
                                                int* route_id) {
  DCHECK(instances_.size() == 1);  // Only called when one process per worker.
  *route_id = WorkerService::GetInstance()->next_worker_route_id();
  WorkerService::GetInstance()->CreateDedicatedWorker(
      url, instances_.front().renderer_process_id,
      instances_.front().render_view_route_id, this, GetProcessId(), *route_id);
}

void WorkerProcessHost::OnCancelCreateDedicatedWorker(int route_id) {
  WorkerService::GetInstance()->CancelCreateDedicatedWorker(
      GetProcessId(), route_id);
}

void WorkerProcessHost::OnForwardToWorker(const IPC::Message& message) {
  WorkerService::GetInstance()->ForwardMessage(message, GetProcessId());
}
<commit_msg>Get rid of warning on CHROME_OS builder. Review URL: http://codereview.chromium.org/165080<commit_after>// Copyright (c) 2009 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/worker_host/worker_process_host.h"

#include <set>

#include "base/command_line.h"
#include "base/debug_util.h"
#if defined(OS_POSIX)
#include "base/global_descriptors_posix.h"
#endif
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/worker_host/message_port_dispatcher.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/debug_flags.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/result_codes.h"
#include "chrome/common/worker_messages.h"
#include "ipc/ipc_descriptors.h"
#include "ipc/ipc_switches.h"
#include "net/base/registry_controlled_domain.h"

#if defined(OS_WIN)
#include "chrome/browser/sandbox_policy.h"
#endif

// Notifies RenderViewHost that one or more worker objects crashed.
class WorkerCrashTask : public Task {
 public:
  WorkerCrashTask(int render_process_id, int render_view_id)
      : render_process_id_(render_process_id),
        render_view_id_(render_view_id) { }

  void Run() {
    RenderViewHost* host =
        RenderViewHost::FromID(render_process_id_, render_view_id_);
    if (host) {
      RenderViewHostDelegate::BrowserIntegration* integration_delegate =
          host->delegate()->GetBrowserIntegrationDelegate();
      if (integration_delegate)
        integration_delegate->OnCrashedWorker();
    }
  }

 private:
  int render_process_id_;
  int render_view_id_;
};

WorkerProcessHost::WorkerProcessHost(
    ResourceDispatcherHost* resource_dispatcher_host_)
    : ChildProcessHost(WORKER_PROCESS, resource_dispatcher_host_) {
  next_route_id_callback_.reset(NewCallbackWithReturnValue(
      WorkerService::GetInstance(), &WorkerService::next_worker_route_id));
}

WorkerProcessHost::~WorkerProcessHost() {
  // Let interested observers know we are being deleted.
  NotificationService::current()->Notify(
      NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
      Source<WorkerProcessHost>(this),
      NotificationService::NoDetails());

  // If we crashed, tell the RenderViewHost.
  MessageLoop* ui_loop = WorkerService::GetInstance()->ui_loop();
  for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
    ui_loop->PostTask(FROM_HERE, new WorkerCrashTask(
        i->renderer_process_id, i->render_view_route_id));
  }

  ChildProcessSecurityPolicy::GetInstance()->Remove(GetProcessId());
}

bool WorkerProcessHost::Init() {
  if (!CreateChannel())
    return false;

  std::wstring exe_path;
  if (!PathService::Get(base::FILE_EXE, &exe_path))
    return false;

  CommandLine cmd_line(exe_path);
  cmd_line.AppendSwitchWithValue(switches::kProcessType,
                                 switches::kWorkerProcess);
  cmd_line.AppendSwitchWithValue(switches::kProcessChannelID,
                                 ASCIIToWide(channel_id()));

  if (CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableNativeWebWorkers)) {
    cmd_line.AppendSwitch(switches::kEnableNativeWebWorkers);
  }

  if (CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kWebWorkerShareProcesses)) {
    cmd_line.AppendSwitch(switches::kWebWorkerShareProcesses);
  }

  base::ProcessHandle process;
#if defined(OS_WIN)
  process = sandbox::StartProcess(&cmd_line);
#else
  // This code is duplicated with browser_render_process_host.cc, but
  // there's not a good place to de-duplicate it.
  base::file_handle_mapping_vector fds_to_map;
  const int ipcfd = channel().GetClientFileDescriptor();
  if (ipcfd > -1) {
    fds_to_map.push_back(std::pair<int, int>(
        ipcfd, kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
  }
  base::LaunchApp(cmd_line.argv(), fds_to_map, false, &process);
#endif
  if (!process)
    return false;
  SetHandle(process);

  ChildProcessSecurityPolicy::GetInstance()->Add(GetProcessId());

  return true;
}

void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
  ChildProcessSecurityPolicy::GetInstance()->GrantRequestURL(
      GetProcessId(), instance.url);

  instances_.push_back(instance);
  Send(new WorkerProcessMsg_CreateWorker(
      instance.url, instance.worker_route_id));

  UpdateTitle();
  instances_.back().sender->Send(
      new ViewMsg_DedicatedWorkerCreated(instance.sender_route_id));
}

bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
                                      int sender_pid) {
  for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
    if (i->sender_pid == sender_pid &&
        i->sender_route_id == message.routing_id()) {
      RelayMessage(
          message, this, i->worker_route_id, next_route_id_callback_.get());
      return true;
    }
  }

  return false;
}

URLRequestContext* WorkerProcessHost::GetRequestContext(
    uint32 request_id,
    const ViewHostMsg_Resource_Request& request_data) {
  return NULL;
}

void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
  bool msg_is_ok = true;
  bool handled = MessagePortDispatcher::GetInstance()->OnMessageReceived(
      message, this, next_route_id_callback_.get(), &msg_is_ok);

  if (!handled) {
    handled = true;
    IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok)
      IPC_MESSAGE_HANDLER(ViewHostMsg_CreateDedicatedWorker,
                          OnCreateDedicatedWorker)
      IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker,
                          OnCancelCreateDedicatedWorker)
      IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker,
                          OnForwardToWorker)
      IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP_EX()
  }

  if (!msg_is_ok) {
    NOTREACHED();
    base::KillProcess(handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
  }

  if (handled)
    return;

  for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
    if (i->worker_route_id == message.routing_id()) {
      CallbackWithReturnValue<int>::Type* next_route_id =
          GetNextRouteIdCallback(i->sender);
      RelayMessage(message, i->sender, i->sender_route_id, next_route_id);

      if (message.type() == WorkerHostMsg_WorkerContextDestroyed::ID) {
        instances_.erase(i);
        UpdateTitle();
      }
      break;
    }
  }
}

CallbackWithReturnValue<int>::Type* WorkerProcessHost::GetNextRouteIdCallback(
    IPC::Message::Sender* sender) {
  // We don't keep callbacks for senders associated with workers, so figure out
  // what kind of sender this is, and cast it to the correct class to get the
  // callback.
  for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
       !iter.Done(); ++iter) {
    WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
    if (static_cast<IPC::Message::Sender*>(worker) == sender)
      return worker->next_route_id_callback_.get();
  }

  // Must be a ResourceMessageFilter.
  return static_cast<ResourceMessageFilter*>(sender)->next_route_id_callback();
}

void WorkerProcessHost::RelayMessage(
    const IPC::Message& message,
    IPC::Message::Sender* sender,
    int route_id,
    CallbackWithReturnValue<int>::Type* next_route_id) {
  IPC::Message* new_message;
  if (message.type() == WorkerMsg_PostMessage::ID) {
    // We want to send the receiver a routing id for the new channel, so
    // crack the message first.
    string16 msg;
    int sent_message_port_id = MSG_ROUTING_NONE;
    int new_routing_id = MSG_ROUTING_NONE;
    if (!WorkerMsg_PostMessage::Read(
            &message, &msg, &sent_message_port_id, &new_routing_id)) {
      return;
    }

    if (sent_message_port_id != MSG_ROUTING_NONE) {
      new_routing_id = next_route_id->Run();
      MessagePortDispatcher::GetInstance()->UpdateMessagePort(
          sent_message_port_id, sender, new_routing_id, next_route_id);
    }

    new_message = new WorkerMsg_PostMessage(
        route_id, msg, sent_message_port_id, new_routing_id);
  } else {
    new_message = new IPC::Message(message);
    new_message->set_routing_id(route_id);
  }

  sender->Send(new_message);
}

void WorkerProcessHost::SenderShutdown(IPC::Message::Sender* sender) {
  for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
    if (i->sender == sender) {
      Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id));
      i = instances_.erase(i);
    } else {
      ++i;
    }
  }
}

void WorkerProcessHost::UpdateTitle() {
  std::set<std::string> titles;
  for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
    std::string title =
        net::RegistryControlledDomainService::GetDomainAndRegistry(i->url);
    // Use the host name if the domain is empty, i.e. localhost or IP address.
    if (title.empty())
      title = i->url.host();
    // If the host name is empty, i.e. file url, use the path.
    if (title.empty())
      title = i->url.path();
    titles.insert(title);
  }

  std::string display_title;
  for (std::set<std::string>::iterator i = titles.begin();
       i != titles.end(); ++i) {
    if (!display_title.empty())
      display_title += ", ";
    display_title += *i;
  }

  set_name(ASCIIToWide(display_title));
}

void WorkerProcessHost::OnCreateDedicatedWorker(const GURL& url,
                                                int render_view_route_id,
                                                int* route_id) {
  DCHECK(instances_.size() == 1);  // Only called when one process per worker.
  *route_id = WorkerService::GetInstance()->next_worker_route_id();
  WorkerService::GetInstance()->CreateDedicatedWorker(
      url, instances_.front().renderer_process_id,
      instances_.front().render_view_route_id, this, GetProcessId(), *route_id);
}

void WorkerProcessHost::OnCancelCreateDedicatedWorker(int route_id) {
  WorkerService::GetInstance()->CancelCreateDedicatedWorker(
      GetProcessId(), route_id);
}

void WorkerProcessHost::OnForwardToWorker(const IPC::Message& message) {
  WorkerService::GetInstance()->ForwardMessage(message, GetProcessId());
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 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/service/net/service_url_request_context.h"

#if defined(OS_POSIX) && !defined(OS_MACOSX)
#include <sys/utsname.h>
#endif

#include "base/compiler_specific.h"
#include "base/message_loop_proxy.h"
#include "base/stringprintf.h"
#include "base/sys_info.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/service/service_process.h"
#include "net/base/cert_verifier.h"
#include "net/base/host_resolver.h"
#include "net/base/ssl_config_service_defaults.h"
#include "net/cookies/cookie_monster.h"
#include "net/ftp/ftp_network_layer.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_session.h"
#include "net/http/http_server_properties_impl.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_service.h"

namespace {
// Copied from webkit/glue/user_agent.cc. We don't want to pull in a dependency
// on webkit/glue which also pulls in the renderer. Also our user-agent is
// totally different from the user-agent used by the browser, just the
// OS-specific parts are common.
std::string BuildOSCpuInfo() {
  std::string os_cpu;

#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
  int32 os_major_version = 0;
  int32 os_minor_version = 0;
  int32 os_bugfix_version = 0;
  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
                                               &os_minor_version,
                                               &os_bugfix_version);
#endif
#if defined(OS_POSIX) && !defined(OS_MACOSX)
  // Should work on any Posix system.
  struct utsname unixinfo;
  uname(&unixinfo);

  std::string cputype;
  // special case for biarch systems
  if (strcmp(unixinfo.machine, "x86_64") == 0 &&
      sizeof(void*) == sizeof(int32)) {  // NOLINT
    cputype.assign("i686 (x86_64)");
  } else {
    cputype.assign(unixinfo.machine);
  }
#endif

  base::StringAppendF(
      &os_cpu,
#if defined(OS_WIN)
      "Windows NT %d.%d",
      os_major_version,
      os_minor_version
#elif defined(OS_MACOSX)
      "Intel Mac OS X %d_%d_%d",
      os_major_version,
      os_minor_version,
      os_bugfix_version
#elif defined(OS_CHROMEOS)
      "CrOS %s %d.%d.%d",
      cputype.c_str(),  // e.g. i686
      os_major_version,
      os_minor_version,
      os_bugfix_version
#else
      "%s %s",
      unixinfo.sysname,  // e.g. Linux
      cputype.c_str()    // e.g. i686
#endif
  );  // NOLINT

  return os_cpu;
}

std::string MakeUserAgentForServiceProcess() {
  std::string user_agent;
  chrome::VersionInfo version_info;
  if (!version_info.is_valid()) {
    DLOG(ERROR) << "Unable to create chrome::VersionInfo object";
  }
  std::string extra_version_info;
  if (!version_info.IsOfficialBuild())
    extra_version_info = "-devel";
  base::StringAppendF(&user_agent,
                      "Chrome Service %s(%s)%s %s ",
                      version_info.Version().c_str(),
                      version_info.LastChange().c_str(),
                      extra_version_info.c_str(),
                      BuildOSCpuInfo().c_str());
  return user_agent;
}

}  // namespace

ServiceURLRequestContext::ServiceURLRequestContext(
    const std::string& user_agent,
    net::ProxyConfigService* net_proxy_config_service)
    : user_agent_(user_agent),
      ALLOW_THIS_IN_INITIALIZER_LIST(storage_(this)) {
  storage_.set_host_resolver(
      net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
                                    net::HostResolver::kDefaultRetryAttempts,
                                    NULL));
  storage_.set_proxy_service(net::ProxyService::CreateUsingSystemProxyResolver(
      net_proxy_config_service, 0u, NULL));
  storage_.set_cert_verifier(net::CertVerifier::CreateDefault());
  storage_.set_ftp_transaction_factory(
      new net::FtpNetworkLayer(host_resolver()));
  storage_.set_ssl_config_service(new net::SSLConfigServiceDefaults);
  storage_.set_http_auth_handler_factory(
      net::HttpAuthHandlerFactory::CreateDefault(host_resolver()));
  storage_.set_http_server_properties(new net::HttpServerPropertiesImpl);
  storage_.set_transport_security_state(new net::TransportSecurityState);

  net::HttpNetworkSession::Params session_params;
  session_params.host_resolver = host_resolver();
  session_params.cert_verifier = cert_verifier();
  session_params.proxy_service = proxy_service();
  session_params.ssl_config_service = ssl_config_service();
  session_params.http_auth_handler_factory = http_auth_handler_factory();
  session_params.http_server_properties = http_server_properties();
  scoped_refptr<net::HttpNetworkSession> network_session(
      new net::HttpNetworkSession(session_params));
  storage_.set_http_transaction_factory(
      new net::HttpCache(
          network_session,
          net::HttpCache::DefaultBackend::InMemory(0)));
  // In-memory cookie store.
  storage_.set_cookie_store(new net::CookieMonster(NULL, NULL));
  set_accept_language("en-us,fr");
  set_accept_charset("iso-8859-1,*,utf-8");
}

const std::string& ServiceURLRequestContext::GetUserAgent(
    const GURL& url) const {
  // If the user agent is set explicitly return that, otherwise call the
  // base class method to return default value.
  return user_agent_.empty() ?
      net::URLRequestContext::GetUserAgent(url) : user_agent_;
}

ServiceURLRequestContext::~ServiceURLRequestContext() {
}

ServiceURLRequestContextGetter::ServiceURLRequestContextGetter()
    : network_task_runner_(
          g_service_process->io_thread()->message_loop_proxy()) {
  // Build the default user agent.
  user_agent_ = MakeUserAgentForServiceProcess();

  // TODO(sanjeevr): Change CreateSystemProxyConfigService to accept a
  // MessageLoopProxy* instead of MessageLoop*.
  DCHECK(g_service_process);
  proxy_config_service_.reset(
      net::ProxyService::CreateSystemProxyConfigService(
          g_service_process->io_thread()->message_loop_proxy(),
          g_service_process->file_thread()->message_loop()));
}

net::URLRequestContext*
ServiceURLRequestContextGetter::GetURLRequestContext() {
  if (!url_request_context_.get())
    url_request_context_.reset(
        new ServiceURLRequestContext(user_agent_,
                                     proxy_config_service_.release()));
  return url_request_context_.get();
}

scoped_refptr<base::SingleThreadTaskRunner>
ServiceURLRequestContextGetter::GetNetworkTaskRunner() const {
  return network_task_runner_;
}

ServiceURLRequestContextGetter::~ServiceURLRequestContextGetter() {}
<commit_msg>Bring back service process throttler.<commit_after>// Copyright (c) 2012 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/service/net/service_url_request_context.h"

#if defined(OS_POSIX) && !defined(OS_MACOSX)
#include <sys/utsname.h>
#endif

#include "base/compiler_specific.h"
#include "base/message_loop_proxy.h"
#include "base/stringprintf.h"
#include "base/sys_info.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/service/service_process.h"
#include "net/base/cert_verifier.h"
#include "net/base/host_resolver.h"
#include "net/base/ssl_config_service_defaults.h"
#include "net/cookies/cookie_monster.h"
#include "net/ftp/ftp_network_layer.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_session.h"
#include "net/http/http_server_properties_impl.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_throttler_manager.h"

namespace {
// Copied from webkit/glue/user_agent.cc. We don't want to pull in a dependency
// on webkit/glue which also pulls in the renderer. Also our user-agent is
// totally different from the user-agent used by the browser, just the
// OS-specific parts are common.
std::string BuildOSCpuInfo() {
  std::string os_cpu;

#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
  int32 os_major_version = 0;
  int32 os_minor_version = 0;
  int32 os_bugfix_version = 0;
  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
                                               &os_minor_version,
                                               &os_bugfix_version);
#endif
#if defined(OS_POSIX) && !defined(OS_MACOSX)
  // Should work on any Posix system.
  struct utsname unixinfo;
  uname(&unixinfo);

  std::string cputype;
  // special case for biarch systems
  if (strcmp(unixinfo.machine, "x86_64") == 0 &&
      sizeof(void*) == sizeof(int32)) {  // NOLINT
    cputype.assign("i686 (x86_64)");
  } else {
    cputype.assign(unixinfo.machine);
  }
#endif

  base::StringAppendF(
      &os_cpu,
#if defined(OS_WIN)
      "Windows NT %d.%d",
      os_major_version,
      os_minor_version
#elif defined(OS_MACOSX)
      "Intel Mac OS X %d_%d_%d",
      os_major_version,
      os_minor_version,
      os_bugfix_version
#elif defined(OS_CHROMEOS)
      "CrOS %s %d.%d.%d",
      cputype.c_str(),  // e.g. i686
      os_major_version,
      os_minor_version,
      os_bugfix_version
#else
      "%s %s",
      unixinfo.sysname,  // e.g. Linux
      cputype.c_str()    // e.g. i686
#endif
  );  // NOLINT

  return os_cpu;
}

std::string MakeUserAgentForServiceProcess() {
  std::string user_agent;
  chrome::VersionInfo version_info;
  if (!version_info.is_valid()) {
    DLOG(ERROR) << "Unable to create chrome::VersionInfo object";
  }
  std::string extra_version_info;
  if (!version_info.IsOfficialBuild())
    extra_version_info = "-devel";
  base::StringAppendF(&user_agent,
                      "Chrome Service %s(%s)%s %s ",
                      version_info.Version().c_str(),
                      version_info.LastChange().c_str(),
                      extra_version_info.c_str(),
                      BuildOSCpuInfo().c_str());
  return user_agent;
}

}  // namespace

ServiceURLRequestContext::ServiceURLRequestContext(
    const std::string& user_agent,
    net::ProxyConfigService* net_proxy_config_service)
    : user_agent_(user_agent),
      ALLOW_THIS_IN_INITIALIZER_LIST(storage_(this)) {
  storage_.set_host_resolver(
      net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
                                    net::HostResolver::kDefaultRetryAttempts,
                                    NULL));
  storage_.set_proxy_service(net::ProxyService::CreateUsingSystemProxyResolver(
      net_proxy_config_service, 0u, NULL));
  storage_.set_cert_verifier(net::CertVerifier::CreateDefault());
  storage_.set_ftp_transaction_factory(
      new net::FtpNetworkLayer(host_resolver()));
  storage_.set_ssl_config_service(new net::SSLConfigServiceDefaults);
  storage_.set_http_auth_handler_factory(
      net::HttpAuthHandlerFactory::CreateDefault(host_resolver()));
  storage_.set_http_server_properties(new net::HttpServerPropertiesImpl);
  storage_.set_transport_security_state(new net::TransportSecurityState);
  storage_.set_throttler_manager(new net::URLRequestThrottlerManager);

  net::HttpNetworkSession::Params session_params;
  session_params.host_resolver = host_resolver();
  session_params.cert_verifier = cert_verifier();
  session_params.proxy_service = proxy_service();
  session_params.ssl_config_service = ssl_config_service();
  session_params.http_auth_handler_factory = http_auth_handler_factory();
  session_params.http_server_properties = http_server_properties();
  scoped_refptr<net::HttpNetworkSession> network_session(
      new net::HttpNetworkSession(session_params));
  storage_.set_http_transaction_factory(
      new net::HttpCache(
          network_session,
          net::HttpCache::DefaultBackend::InMemory(0)));
  // In-memory cookie store.
  storage_.set_cookie_store(new net::CookieMonster(NULL, NULL));
  set_accept_language("en-us,fr");
  set_accept_charset("iso-8859-1,*,utf-8");
}

const std::string& ServiceURLRequestContext::GetUserAgent(
    const GURL& url) const {
  // If the user agent is set explicitly return that, otherwise call the
  // base class method to return default value.
  return user_agent_.empty() ?
      net::URLRequestContext::GetUserAgent(url) : user_agent_;
}

ServiceURLRequestContext::~ServiceURLRequestContext() {
}

ServiceURLRequestContextGetter::ServiceURLRequestContextGetter()
    : network_task_runner_(
          g_service_process->io_thread()->message_loop_proxy()) {
  // Build the default user agent.
  user_agent_ = MakeUserAgentForServiceProcess();

  // TODO(sanjeevr): Change CreateSystemProxyConfigService to accept a
  // MessageLoopProxy* instead of MessageLoop*.
  DCHECK(g_service_process);
  proxy_config_service_.reset(
      net::ProxyService::CreateSystemProxyConfigService(
          g_service_process->io_thread()->message_loop_proxy(),
          g_service_process->file_thread()->message_loop()));
}

net::URLRequestContext*
ServiceURLRequestContextGetter::GetURLRequestContext() {
  if (!url_request_context_.get())
    url_request_context_.reset(
        new ServiceURLRequestContext(user_agent_,
                                     proxy_config_service_.release()));
  return url_request_context_.get();
}

scoped_refptr<base::SingleThreadTaskRunner>
ServiceURLRequestContextGetter::GetNetworkTaskRunner() const {
  return network_task_runner_;
}

ServiceURLRequestContextGetter::~ServiceURLRequestContextGetter() {}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
//  HTTPFileSystemTest.cc
//  Test HTTP file system functionality.
//------------------------------------------------------------------------------
#include "Pre.h"
#include "UnitTest++/src/UnitTest++.h"
#include "Core/Core.h"
#include "Core/RunLoop.h"
#include "HTTP/HTTPFileSystem.h"
#include "IO/IO.h"

using namespace Oryol;

#if !ORYOL_EMSCRIPTEN
TEST(HTTPFileSystemTest) {
    Core::Setup();

    // setup an IO facade, and associate http: with the HTTPFileSystem
    IOSetup ioSetup;
    ioSetup.FileSystems.Add("http", HTTPFileSystem::Creator());
    IO::Setup(ioSetup);

    // asynchronously load the index.html file
    Ptr<IORead> req = IO::LoadFile("http://www.flohofwoe.net/index.html");

    // trigger the runloop until the request has been handled
    while (!req->Handled) {
        Core::PreRunLoop()->Run();
    }

    // check what we got
    CHECK(req->Status == IOStatus::OK);
    CHECK(!req->Data.Empty());
    CHECK(req->Data.Size() > 0);
    if (req->Data.Size() > 0) {
        String content((const char*)req->Data.Data(), 0, req->Data.Size());
        Log::Info("%s\n", content.AsCStr());
    }
    req = 0;

    IO::Discard();
    Core::Discard();
}
#endif
<commit_msg>Disable HTTPTest if 'headless', seems to hang travis-ci now<commit_after>//------------------------------------------------------------------------------
//  HTTPFileSystemTest.cc
//  Test HTTP file system functionality.
//------------------------------------------------------------------------------
#include "Pre.h"
#include "UnitTest++/src/UnitTest++.h"
#include "Core/Core.h"
#include "Core/RunLoop.h"
#include "HTTP/HTTPFileSystem.h"
#include "IO/IO.h"

using namespace Oryol;

#if !ORYOL_EMSCRIPTEN && !ORYOL_UNITTESTS_HEADLESS
TEST(HTTPFileSystemTest) {
    Core::Setup();

    // setup an IO facade, and associate http: with the HTTPFileSystem
    IOSetup ioSetup;
    ioSetup.FileSystems.Add("http", HTTPFileSystem::Creator());
    IO::Setup(ioSetup);

    // asynchronously load the index.html file
    Ptr<IORead> req = IO::LoadFile("http://www.flohofwoe.net/index.html");

    // trigger the runloop until the request has been handled
    while (!req->Handled) {
        Core::PreRunLoop()->Run();
    }

    // check what we got
    CHECK(req->Status == IOStatus::OK);
    CHECK(!req->Data.Empty());
    CHECK(req->Data.Size() > 0);
    if (req->Data.Size() > 0) {
        String content((const char*)req->Data.Data(), 0, req->Data.Size());
        Log::Info("%s\n", content.AsCStr());
    }
    req = 0;

    IO::Discard();
    Core::Discard();
}
#endif
<|endoftext|>