<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/browser/nacl_host/nacl_browser.h"

#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "base/win/windows_version.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_paths_internal.h"
#include "content/public/browser/browser_thread.h"

namespace {

// An arbitrary delay to coalesce multiple writes to the cache.
const int kValidationCacheCoalescingTimeMS = 6000;
const char kValidationCacheSequenceName[] = "NaClValidationCache";
const FilePath::CharType kValidationCacheFileName[] =
    FILE_PATH_LITERAL("nacl_validation_cache.bin");

enum ValidationCacheStatus {
  CACHE_MISS = 0,
  CACHE_HIT,
  CACHE_MAX
};

// Determine the name of the IRT file based on the architecture.
#define NACL_IRT_FILE_NAME(arch_string) \
  (FILE_PATH_LITERAL("nacl_irt_")       \
   FILE_PATH_LITERAL(arch_string)       \
   FILE_PATH_LITERAL(".nexe"))

const FilePath::StringType NaClIrtName() {
#if defined(ARCH_CPU_X86_FAMILY)
#if defined(ARCH_CPU_X86_64)
  bool is64 = true;
#elif defined(OS_WIN)
  bool is64 = (base::win::OSInfo::GetInstance()->wow64_status() ==
               base::win::OSInfo::WOW64_ENABLED);
#else
  bool is64 = false;
#endif
  return is64 ? NACL_IRT_FILE_NAME("x86_64") : NACL_IRT_FILE_NAME("x86_32");
#elif defined(ARCH_CPU_ARMEL)
  // TODO(mcgrathr): Eventually we'll need to distinguish arm32 vs thumb2.
  // That may need to be based on the actual nexe rather than a static
  // choice, which would require substantial refactoring.
  return NACL_IRT_FILE_NAME("arm");
#else
#error Add support for your architecture to NaCl IRT file selection
#endif
}

bool CheckEnvVar(const char* name, bool default_value) {
  bool result = default_value;
  const char* var = getenv(name);
  if (var && strlen(var) > 0) {
    result = var[0] != '0';
  }
  return result;
}

void ReadCache(const FilePath& filename, std::string* data) {
  if (!file_util::ReadFileToString(filename, data)) {
    // Zero-size data used as an in-band error code.
    data->clear();
  }
}

void WriteCache(const FilePath& filename, const Pickle* pickle) {
  file_util::WriteFile(filename, static_cast<const char*>(pickle->data()),
                       pickle->size());
}

void LogCacheQuery(ValidationCacheStatus status) {
  UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status, CACHE_MAX);
}

void LogCacheSet(ValidationCacheStatus status) {
  // Bucket zero is reserved for future use.
  UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, CACHE_MAX);
}

}  // namespace

NaClBrowser::NaClBrowser()
    : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
      irt_platform_file_(base::kInvalidPlatformFileValue),
      irt_filepath_(),
      irt_state_(NaClResourceUninitialized),
      validation_cache_file_path_(),
      validation_cache_is_enabled_(CheckEnvVar("NACL_VALIDATION_CACHE", true)),
      validation_cache_is_modified_(false),
      validation_cache_state_(NaClResourceUninitialized),
      ok_(true) {
  InitIrtFilePath();
}

NaClBrowser::~NaClBrowser() {
  if (irt_platform_file_ != base::kInvalidPlatformFileValue)
    base::ClosePlatformFile(irt_platform_file_);
}

void NaClBrowser::InitIrtFilePath() {
  // Allow the IRT library to be overridden via an environment
  // variable.  This allows the NaCl/Chromium integration bot to
  // specify a newly-built IRT rather than using a prebuilt one
  // downloaded via Chromium's DEPS file.  We use the same environment
  // variable that the standalone NaCl PPAPI plugin accepts.
  const char* irt_path_var = getenv("NACL_IRT_LIBRARY");
  if (irt_path_var != NULL) {
    FilePath::StringType path_string(
        irt_path_var, const_cast<const char*>(strchr(irt_path_var, '\0')));
    irt_filepath_ = FilePath(path_string);
  } else {
    FilePath plugin_dir;
    if (!PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &plugin_dir)) {
      DLOG(ERROR) << "Failed to locate the plugins directory, NaCl disabled.";
      MarkAsFailed();
      return;
    }
    irt_filepath_ = plugin_dir.Append(NaClIrtName());
  }
}

NaClBrowser* NaClBrowser::GetInstance() {
  return Singleton<NaClBrowser>::get();
}

bool NaClBrowser::IsReady() const {
  return (IsOk() &&
          irt_state_ == NaClResourceReady &&
          validation_cache_state_ == NaClResourceReady);
}

bool NaClBrowser::IsOk() const {
  return ok_;
}

base::PlatformFile NaClBrowser::IrtFile() const {
  CHECK_EQ(irt_state_, NaClResourceReady);
  CHECK_NE(irt_platform_file_, base::kInvalidPlatformFileValue);
  return irt_platform_file_;
}

void NaClBrowser::EnsureAllResourcesAvailable() {
  EnsureIrtAvailable();
  EnsureValidationCacheAvailable();
}

// Load the IRT async.
void NaClBrowser::EnsureIrtAvailable() {
  if (IsOk() && irt_state_ == NaClResourceUninitialized) {
    irt_state_ = NaClResourceRequested;
    // TODO(ncbray) use blocking pool.
    if (!base::FileUtilProxy::CreateOrOpen(
            content::BrowserThread::GetMessageLoopProxyForThread(
                content::BrowserThread::FILE),
            irt_filepath_,
            base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
            base::Bind(&NaClBrowser::OnIrtOpened,
                       weak_factory_.GetWeakPtr()))) {
      LOG(ERROR) << "Internal error, NaCl disabled.";
      MarkAsFailed();
    }
  }
}

void NaClBrowser::OnIrtOpened(base::PlatformFileError error_code,
                              base::PassPlatformFile file,
                              bool created) {
  DCHECK_EQ(irt_state_, NaClResourceRequested);
  DCHECK(!created);
  if (error_code == base::PLATFORM_FILE_OK) {
    irt_platform_file_ = file.ReleaseValue();
  } else {
    LOG(ERROR) << "Failed to open NaCl IRT file \""
               << irt_filepath_.LossyDisplayName()
               << "\": " << error_code;
    MarkAsFailed();
  }
  irt_state_ = NaClResourceReady;
  CheckWaiting();
}

void NaClBrowser::EnsureValidationCacheAvailable() {
  if (IsOk() && validation_cache_state_ == NaClResourceUninitialized) {
    if (ValidationCacheIsEnabled()) {
      validation_cache_state_ = NaClResourceRequested;

      // Determine where the validation cache resides in the file system.  It
      // exists in Chrome's cache directory and is not tied to any specific
      // profile.
      // Start by finding the user data directory.
      FilePath user_data_dir;
      if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
        RunWithoutValidationCache();
        return;
      }
      // The cache directory may or may not be the user data directory.
      FilePath cache_file_path;
      chrome::GetUserCacheDirectory(user_data_dir, &cache_file_path);
      // Append the base file name to the cache directory.
      validation_cache_file_path_ =
          cache_file_path.Append(kValidationCacheFileName);

      // Structure for carrying data between the callbacks.
      std::string* data = new std::string();
      // We can get away not giving this a sequence ID because this is the first
      // task and further file access will not occur until after we get a
      // response.
      if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
              FROM_HERE,
              base::Bind(ReadCache, validation_cache_file_path_, data),
              base::Bind(&NaClBrowser::OnValidationCacheLoaded,
                         weak_factory_.GetWeakPtr(),
                         base::Owned(data)))) {
        RunWithoutValidationCache();
      }
    } else {
      RunWithoutValidationCache();
    }
  }
}

void NaClBrowser::OnValidationCacheLoaded(const std::string *data) {
  if (data->size() == 0) {
    // No file found.
    validation_cache_.Reset();
  } else {
    Pickle pickle(data->data(), data->size());
    validation_cache_.Deserialize(&pickle);
  }
  validation_cache_state_ = NaClResourceReady;
  CheckWaiting();
}

void NaClBrowser::RunWithoutValidationCache() {
  // Be paranoid.
  validation_cache_.Reset();
  validation_cache_is_enabled_ = false;
  validation_cache_state_ = NaClResourceReady;
  CheckWaiting();
}

void NaClBrowser::CheckWaiting() {
  if (!IsOk() || IsReady()) {
    // Queue the waiting tasks into the message loop.  This helps avoid
    // re-entrancy problems that could occur if the closure was invoked
    // directly.  For example, this could result in use-after-free of the
    // process host.
    for (std::vector<base::Closure>::iterator iter = waiting_.begin();
         iter != waiting_.end(); ++iter) {
      MessageLoop::current()->PostTask(FROM_HERE, *iter);
    }
    waiting_.clear();
  }
}

void NaClBrowser::MarkAsFailed() {
  ok_ = false;
  CheckWaiting();
}

void NaClBrowser::WaitForResources(const base::Closure& reply) {
  waiting_.push_back(reply);
  EnsureAllResourcesAvailable();
  CheckWaiting();
}

const FilePath& NaClBrowser::GetIrtFilePath() {
  return irt_filepath_;
}

bool NaClBrowser::QueryKnownToValidate(const std::string& signature,
                                       bool off_the_record) {
  if (off_the_record) {
    // If we're off the record, don't reorder the main cache.
    return validation_cache_.QueryKnownToValidate(signature, false) ||
        off_the_record_validation_cache_.QueryKnownToValidate(signature, true);
  } else {
    bool result = validation_cache_.QueryKnownToValidate(signature, true);
    LogCacheQuery(result ? CACHE_HIT : CACHE_MISS);
    // Queries can modify the MRU order of the cache.
    MarkValidationCacheAsModified();
    return result;
  }
}

void NaClBrowser::SetKnownToValidate(const std::string& signature,
                                     bool off_the_record) {
  if (off_the_record) {
    off_the_record_validation_cache_.SetKnownToValidate(signature);
  } else {
    validation_cache_.SetKnownToValidate(signature);
    // The number of sets should be equal to the number of cache misses, minus
    // validation failures and successful validations where stubout occurs.
    LogCacheSet(CACHE_HIT);
    MarkValidationCacheAsModified();
  }
}

void NaClBrowser::MarkValidationCacheAsModified() {
  if (!validation_cache_is_modified_) {
    // Wait before persisting to disk.  This can coalesce multiple cache
    // modifications info a single disk write.
    MessageLoop::current()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&NaClBrowser::PersistValidationCache,
                    weak_factory_.GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(kValidationCacheCoalescingTimeMS));
    validation_cache_is_modified_ = true;
  }
}

void NaClBrowser::PersistValidationCache() {
  if (!validation_cache_file_path_.empty()) {
    Pickle* pickle = new Pickle();
    validation_cache_.Serialize(pickle);

    // Pass the serialized data to another thread to write to disk.  File IO is
    // not allowed on the IO thread (which is the thread this method runs on)
    // because it can degrade the responsiveness of the browser.
    // The task is sequenced so that multiple writes happen in order.
    content::BrowserThread::PostBlockingPoolSequencedTask(
        kValidationCacheSequenceName,
        FROM_HERE,
        base::Bind(WriteCache, validation_cache_file_path_,
                   base::Owned(pickle)));
  }
  validation_cache_is_modified_ = false;
}
<commit_msg>Disable validation caching on ChromeOS.<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/browser/nacl_host/nacl_browser.h"

#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "base/win/windows_version.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_paths_internal.h"
#include "content/public/browser/browser_thread.h"

namespace {

// An arbitrary delay to coalesce multiple writes to the cache.
const int kValidationCacheCoalescingTimeMS = 6000;
const char kValidationCacheSequenceName[] = "NaClValidationCache";
const FilePath::CharType kValidationCacheFileName[] =
    FILE_PATH_LITERAL("nacl_validation_cache.bin");

#if defined(CHROMEOS)
// TODO(ncbray) enable on ChromeOS.
// http://code.google.com/p/chromium/issues/detail?id=131218
const bool kValidationCacheEnabledByDefault = false;
#else
const bool kValidationCacheEnabledByDefault = true;
#endif

enum ValidationCacheStatus {
  CACHE_MISS = 0,
  CACHE_HIT,
  CACHE_MAX
};

// Determine the name of the IRT file based on the architecture.
#define NACL_IRT_FILE_NAME(arch_string) \
  (FILE_PATH_LITERAL("nacl_irt_")       \
   FILE_PATH_LITERAL(arch_string)       \
   FILE_PATH_LITERAL(".nexe"))

const FilePath::StringType NaClIrtName() {
#if defined(ARCH_CPU_X86_FAMILY)
#if defined(ARCH_CPU_X86_64)
  bool is64 = true;
#elif defined(OS_WIN)
  bool is64 = (base::win::OSInfo::GetInstance()->wow64_status() ==
               base::win::OSInfo::WOW64_ENABLED);
#else
  bool is64 = false;
#endif
  return is64 ? NACL_IRT_FILE_NAME("x86_64") : NACL_IRT_FILE_NAME("x86_32");
#elif defined(ARCH_CPU_ARMEL)
  // TODO(mcgrathr): Eventually we'll need to distinguish arm32 vs thumb2.
  // That may need to be based on the actual nexe rather than a static
  // choice, which would require substantial refactoring.
  return NACL_IRT_FILE_NAME("arm");
#else
#error Add support for your architecture to NaCl IRT file selection
#endif
}

bool CheckEnvVar(const char* name, bool default_value) {
  bool result = default_value;
  const char* var = getenv(name);
  if (var && strlen(var) > 0) {
    result = var[0] != '0';
  }
  return result;
}

void ReadCache(const FilePath& filename, std::string* data) {
  if (!file_util::ReadFileToString(filename, data)) {
    // Zero-size data used as an in-band error code.
    data->clear();
  }
}

void WriteCache(const FilePath& filename, const Pickle* pickle) {
  file_util::WriteFile(filename, static_cast<const char*>(pickle->data()),
                       pickle->size());
}

void LogCacheQuery(ValidationCacheStatus status) {
  UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status, CACHE_MAX);
}

void LogCacheSet(ValidationCacheStatus status) {
  // Bucket zero is reserved for future use.
  UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, CACHE_MAX);
}

}  // namespace

NaClBrowser::NaClBrowser()
    : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
      irt_platform_file_(base::kInvalidPlatformFileValue),
      irt_filepath_(),
      irt_state_(NaClResourceUninitialized),
      validation_cache_file_path_(),
      validation_cache_is_enabled_(
          CheckEnvVar("NACL_VALIDATION_CACHE",
                      kValidationCacheEnabledByDefault)),
      validation_cache_is_modified_(false),
      validation_cache_state_(NaClResourceUninitialized),
      ok_(true) {
  InitIrtFilePath();
}

NaClBrowser::~NaClBrowser() {
  if (irt_platform_file_ != base::kInvalidPlatformFileValue)
    base::ClosePlatformFile(irt_platform_file_);
}

void NaClBrowser::InitIrtFilePath() {
  // Allow the IRT library to be overridden via an environment
  // variable.  This allows the NaCl/Chromium integration bot to
  // specify a newly-built IRT rather than using a prebuilt one
  // downloaded via Chromium's DEPS file.  We use the same environment
  // variable that the standalone NaCl PPAPI plugin accepts.
  const char* irt_path_var = getenv("NACL_IRT_LIBRARY");
  if (irt_path_var != NULL) {
    FilePath::StringType path_string(
        irt_path_var, const_cast<const char*>(strchr(irt_path_var, '\0')));
    irt_filepath_ = FilePath(path_string);
  } else {
    FilePath plugin_dir;
    if (!PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &plugin_dir)) {
      DLOG(ERROR) << "Failed to locate the plugins directory, NaCl disabled.";
      MarkAsFailed();
      return;
    }
    irt_filepath_ = plugin_dir.Append(NaClIrtName());
  }
}

NaClBrowser* NaClBrowser::GetInstance() {
  return Singleton<NaClBrowser>::get();
}

bool NaClBrowser::IsReady() const {
  return (IsOk() &&
          irt_state_ == NaClResourceReady &&
          validation_cache_state_ == NaClResourceReady);
}

bool NaClBrowser::IsOk() const {
  return ok_;
}

base::PlatformFile NaClBrowser::IrtFile() const {
  CHECK_EQ(irt_state_, NaClResourceReady);
  CHECK_NE(irt_platform_file_, base::kInvalidPlatformFileValue);
  return irt_platform_file_;
}

void NaClBrowser::EnsureAllResourcesAvailable() {
  EnsureIrtAvailable();
  EnsureValidationCacheAvailable();
}

// Load the IRT async.
void NaClBrowser::EnsureIrtAvailable() {
  if (IsOk() && irt_state_ == NaClResourceUninitialized) {
    irt_state_ = NaClResourceRequested;
    // TODO(ncbray) use blocking pool.
    if (!base::FileUtilProxy::CreateOrOpen(
            content::BrowserThread::GetMessageLoopProxyForThread(
                content::BrowserThread::FILE),
            irt_filepath_,
            base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
            base::Bind(&NaClBrowser::OnIrtOpened,
                       weak_factory_.GetWeakPtr()))) {
      LOG(ERROR) << "Internal error, NaCl disabled.";
      MarkAsFailed();
    }
  }
}

void NaClBrowser::OnIrtOpened(base::PlatformFileError error_code,
                              base::PassPlatformFile file,
                              bool created) {
  DCHECK_EQ(irt_state_, NaClResourceRequested);
  DCHECK(!created);
  if (error_code == base::PLATFORM_FILE_OK) {
    irt_platform_file_ = file.ReleaseValue();
  } else {
    LOG(ERROR) << "Failed to open NaCl IRT file \""
               << irt_filepath_.LossyDisplayName()
               << "\": " << error_code;
    MarkAsFailed();
  }
  irt_state_ = NaClResourceReady;
  CheckWaiting();
}

void NaClBrowser::EnsureValidationCacheAvailable() {
  if (IsOk() && validation_cache_state_ == NaClResourceUninitialized) {
    if (ValidationCacheIsEnabled()) {
      validation_cache_state_ = NaClResourceRequested;

      // Determine where the validation cache resides in the file system.  It
      // exists in Chrome's cache directory and is not tied to any specific
      // profile.
      // Start by finding the user data directory.
      FilePath user_data_dir;
      if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
        RunWithoutValidationCache();
        return;
      }
      // The cache directory may or may not be the user data directory.
      FilePath cache_file_path;
      chrome::GetUserCacheDirectory(user_data_dir, &cache_file_path);
      // Append the base file name to the cache directory.
      validation_cache_file_path_ =
          cache_file_path.Append(kValidationCacheFileName);

      // Structure for carrying data between the callbacks.
      std::string* data = new std::string();
      // We can get away not giving this a sequence ID because this is the first
      // task and further file access will not occur until after we get a
      // response.
      if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
              FROM_HERE,
              base::Bind(ReadCache, validation_cache_file_path_, data),
              base::Bind(&NaClBrowser::OnValidationCacheLoaded,
                         weak_factory_.GetWeakPtr(),
                         base::Owned(data)))) {
        RunWithoutValidationCache();
      }
    } else {
      RunWithoutValidationCache();
    }
  }
}

void NaClBrowser::OnValidationCacheLoaded(const std::string *data) {
  if (data->size() == 0) {
    // No file found.
    validation_cache_.Reset();
  } else {
    Pickle pickle(data->data(), data->size());
    validation_cache_.Deserialize(&pickle);
  }
  validation_cache_state_ = NaClResourceReady;
  CheckWaiting();
}

void NaClBrowser::RunWithoutValidationCache() {
  // Be paranoid.
  validation_cache_.Reset();
  validation_cache_is_enabled_ = false;
  validation_cache_state_ = NaClResourceReady;
  CheckWaiting();
}

void NaClBrowser::CheckWaiting() {
  if (!IsOk() || IsReady()) {
    // Queue the waiting tasks into the message loop.  This helps avoid
    // re-entrancy problems that could occur if the closure was invoked
    // directly.  For example, this could result in use-after-free of the
    // process host.
    for (std::vector<base::Closure>::iterator iter = waiting_.begin();
         iter != waiting_.end(); ++iter) {
      MessageLoop::current()->PostTask(FROM_HERE, *iter);
    }
    waiting_.clear();
  }
}

void NaClBrowser::MarkAsFailed() {
  ok_ = false;
  CheckWaiting();
}

void NaClBrowser::WaitForResources(const base::Closure& reply) {
  waiting_.push_back(reply);
  EnsureAllResourcesAvailable();
  CheckWaiting();
}

const FilePath& NaClBrowser::GetIrtFilePath() {
  return irt_filepath_;
}

bool NaClBrowser::QueryKnownToValidate(const std::string& signature,
                                       bool off_the_record) {
  if (off_the_record) {
    // If we're off the record, don't reorder the main cache.
    return validation_cache_.QueryKnownToValidate(signature, false) ||
        off_the_record_validation_cache_.QueryKnownToValidate(signature, true);
  } else {
    bool result = validation_cache_.QueryKnownToValidate(signature, true);
    LogCacheQuery(result ? CACHE_HIT : CACHE_MISS);
    // Queries can modify the MRU order of the cache.
    MarkValidationCacheAsModified();
    return result;
  }
}

void NaClBrowser::SetKnownToValidate(const std::string& signature,
                                     bool off_the_record) {
  if (off_the_record) {
    off_the_record_validation_cache_.SetKnownToValidate(signature);
  } else {
    validation_cache_.SetKnownToValidate(signature);
    // The number of sets should be equal to the number of cache misses, minus
    // validation failures and successful validations where stubout occurs.
    LogCacheSet(CACHE_HIT);
    MarkValidationCacheAsModified();
  }
}

void NaClBrowser::MarkValidationCacheAsModified() {
  if (!validation_cache_is_modified_) {
    // Wait before persisting to disk.  This can coalesce multiple cache
    // modifications info a single disk write.
    MessageLoop::current()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&NaClBrowser::PersistValidationCache,
                    weak_factory_.GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(kValidationCacheCoalescingTimeMS));
    validation_cache_is_modified_ = true;
  }
}

void NaClBrowser::PersistValidationCache() {
  if (!validation_cache_file_path_.empty()) {
    Pickle* pickle = new Pickle();
    validation_cache_.Serialize(pickle);

    // Pass the serialized data to another thread to write to disk.  File IO is
    // not allowed on the IO thread (which is the thread this method runs on)
    // because it can degrade the responsiveness of the browser.
    // The task is sequenced so that multiple writes happen in order.
    content::BrowserThread::PostBlockingPoolSequencedTask(
        kValidationCacheSequenceName,
        FROM_HERE,
        base::Bind(WriteCache, validation_cache_file_path_,
                   base::Owned(pickle)));
  }
  validation_cache_is_modified_ = false;
}
<|endoftext|>


<commit_before><commit_msg>Remove unused variable<commit_after><|endoftext|>


<commit_before><commit_msg>Fix compile failure in pdf_extension_test.cc on branch 2454.<commit_after><|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 "base/file_util.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/snapshot_tab_helper.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "net/test/test_server.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/screen.h"

using content::NavigationController;
using content::WebContents;

namespace {

// Include things like browser frame and scrollbar and make sure we're bigger
// than the test pdf document.
static const int kBrowserWidth = 1000;
static const int kBrowserHeight = 600;

class PDFBrowserTest : public InProcessBrowserTest,
                       public content::NotificationObserver {
 public:
  PDFBrowserTest()
      : snapshot_different_(true),
        next_dummy_search_value_(0),
        load_stop_notification_count_(0) {
    pdf_test_server_.reset(new net::TestServer(
        net::TestServer::TYPE_HTTP,
        net::TestServer::kLocalhost,
        FilePath(FILE_PATH_LITERAL("pdf/test"))));
  }

 protected:
  // Use our own TestServer so that we can serve files from the pdf directory.
  net::TestServer* pdf_test_server() { return pdf_test_server_.get(); }

  int load_stop_notification_count() const {
    return load_stop_notification_count_;
  }

  FilePath GetPDFTestDir() {
    return FilePath(FilePath::kCurrentDirectory).AppendASCII("..").
        AppendASCII("..").AppendASCII("..").AppendASCII("pdf").
        AppendASCII("test");
  }

  void Load() {
    // Make sure to set the window size before rendering, as otherwise rendering
    // to a smaller window and then expanding leads to slight anti-aliasing
    // differences of the text and the pixel comparison fails.
    gfx::Rect bounds(gfx::Rect(0, 0, kBrowserWidth, kBrowserHeight));
    gfx::Rect screen_bounds = gfx::Screen::GetPrimaryDisplay().bounds();
    ASSERT_GT(screen_bounds.width(), kBrowserWidth);
    ASSERT_GT(screen_bounds.height(), kBrowserHeight);
    browser()->window()->SetBounds(bounds);

    GURL url(ui_test_utils::GetTestUrl(
        GetPDFTestDir(),
        FilePath(FILE_PATH_LITERAL("pdf_browsertest.pdf"))));
    ui_test_utils::NavigateToURL(browser(), url);
  }

  void VerifySnapshot(const std::string& expected_filename) {
    snapshot_different_ = true;
    expected_filename_ = expected_filename;
    TabContents* tab_contents =  chrome::GetActiveTabContents(browser());
    tab_contents->snapshot_tab_helper()->CaptureSnapshot();
    ui_test_utils::RegisterAndWait(
        this,
        chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN,
        content::Source<WebContents>(tab_contents->web_contents()));
    ASSERT_FALSE(snapshot_different_) << "Rendering didn't match, see result "
        "at " << snapshot_filename_.value().c_str();
  }

  void WaitForResponse() {
    // Even if the plugin has loaded the data or scrolled, because of how
    // pepper painting works, we might not have the data.  One way to force this
    // to be flushed is to do a find operation, since on this two-page test
    // document, it'll wait for us to flush the renderer message loop twice and
    // also the browser's once, at which point we're guaranteed to have updated
    // the backingstore.  Hacky, but it works.
    // Note that we need to change the text each time, because if we don't the
    // renderer code will think the second message is to go to next result, but
    // there are none so the plugin will assert.

    string16 query = UTF8ToUTF16(
        std::string("xyzxyz" + base::IntToString(next_dummy_search_value_++)));
    ASSERT_EQ(0, ui_test_utils::FindInPage(
        chrome::GetActiveTabContents(browser()), query, true, false, NULL));
  }

 private:
  // content::NotificationObserver
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) {
    if (type == chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN) {
      MessageLoopForUI::current()->Quit();
      FilePath reference = ui_test_utils::GetTestFilePath(
          GetPDFTestDir(),
          FilePath().AppendASCII(expected_filename_));
      base::PlatformFileInfo info;
      ASSERT_TRUE(file_util::GetFileInfo(reference, &info));
      int size = static_cast<size_t>(info.size);
      scoped_array<char> data(new char[size]);
      ASSERT_EQ(size, file_util::ReadFile(reference, data.get(), size));

      int w, h;
      std::vector<unsigned char> decoded;
      ASSERT_TRUE(gfx::PNGCodec::Decode(
          reinterpret_cast<unsigned char*>(data.get()), size,
          gfx::PNGCodec::FORMAT_BGRA, &decoded, &w, &h));
      int32* ref_pixels = reinterpret_cast<int32*>(&decoded[0]);

      const SkBitmap* bitmap = content::Details<const SkBitmap>(details).ptr();
      int32* pixels = static_cast<int32*>(bitmap->getPixels());

      // Get the background color, and use it to figure out the x-offsets in
      // each image.  The reason is that depending on the theme in the OS, the
      // same browser width can lead to slightly different plugin sizes, so the
      // pdf content will start at different x offsets.
      // Also note that the images we saved are cut off before the scrollbar, as
      // that'll change depending on the theme, and also cut off vertically so
      // that the ui controls don't show up, as those fade-in and so the timing
      // will affect their transparency.
      int32 bg_color = ref_pixels[0];
      int ref_x_offset, snapshot_x_offset;
      for (ref_x_offset = 0; ref_x_offset < w; ++ref_x_offset) {
        if (ref_pixels[ref_x_offset] != bg_color)
          break;
      }

      for (snapshot_x_offset = 0; snapshot_x_offset < bitmap->width();
           ++snapshot_x_offset) {
        if (pixels[snapshot_x_offset] != bg_color)
          break;
      }

      int x_max = std::min(
          w - ref_x_offset, bitmap->width() - snapshot_x_offset);
      int y_max = std::min(h, bitmap->height());
      int stride = bitmap->rowBytes();
      snapshot_different_ = false;
      for (int y = 0; y < y_max && !snapshot_different_; ++y) {
        for (int x = 0; x < x_max && !snapshot_different_; ++x) {
          if (pixels[y * stride / sizeof(int32) + x + snapshot_x_offset] !=
              ref_pixels[y * w + x + ref_x_offset])
            snapshot_different_ = true;
        }
      }

      if (snapshot_different_) {
        std::vector<unsigned char> png_data;
        gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &png_data);
        if (file_util::CreateTemporaryFile(&snapshot_filename_)) {
          file_util::WriteFile(snapshot_filename_,
              reinterpret_cast<char*>(&png_data[0]), png_data.size());
        }
      }
    } else if (type == content::NOTIFICATION_LOAD_STOP) {
      load_stop_notification_count_++;
    }
  }

  // True if the snapshot differed from the expected value.
  bool snapshot_different_;
  // Internal variable used to synchronize to the renderer.
  int next_dummy_search_value_;
  // The filename of the bitmap to compare the snapshot to.
  std::string expected_filename_;
  // If the snapshot is different, holds the location where it's saved.
  FilePath snapshot_filename_;
  // How many times we've seen chrome::LOAD_STOP.
  int load_stop_notification_count_;

  scoped_ptr<net::TestServer> pdf_test_server_;
};

#if defined(OS_CHROMEOS)
// TODO(sanjeevr): http://crbug.com/79837
#define MAYBE_Basic DISABLED_Basic
#elif defined(OS_MACOSX)
// Fails on release builder for Mac: http://crbug.com/142531
#define MAYBE_Basic DISABLED_Basic
#else
#define MAYBE_Basic Basic
#endif
// Tests basic PDF rendering.  This can be broken depending on bad merges with
// the vendor, so it's important that we have basic sanity checking.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Basic) {
  ASSERT_NO_FATAL_FAILURE(Load());
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());
  // OS X uses CoreText, and FreeType renders slightly different on Linux and
  // Win.
#if defined(OS_MACOSX)
  std::string expectation_file = "pdf_browsertest_mac.png";
#elif defined(OS_LINUX)
  std::string expectation_file = "pdf_browsertest_linux.png";
#else
  std::string expectation_file = "pdf_browsertest.png";
#endif
  ASSERT_NO_FATAL_FAILURE(VerifySnapshot(expectation_file));
}

#if defined(OS_CHROMEOS)
// TODO(sanjeevr): http://crbug.com/79837
#define MAYBE_Scroll DISABLED_Scroll
#else
#define MAYBE_Scroll Scroll
#endif
// Tests that scrolling works.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Scroll) {
  ASSERT_NO_FATAL_FAILURE(Load());

  // We use wheel mouse event since that's the only one we can easily push to
  // the renderer.  There's no way to push a cross-platform keyboard event at
  // the moment.
  WebKit::WebMouseWheelEvent wheel_event;
  wheel_event.type = WebKit::WebInputEvent::MouseWheel;
  wheel_event.deltaY = -200;
  wheel_event.wheelTicksY = -2;
  WebContents* web_contents = chrome::GetActiveWebContents(browser());
  web_contents->GetRenderViewHost()->ForwardWheelEvent(wheel_event);
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());

  int y_offset = 0;
  ASSERT_TRUE(content::ExecuteJavaScriptAndExtractInt(
      chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
      std::wstring(),
      L"window.domAutomationController.send(plugin.pageYOffset())",
      &y_offset));
  ASSERT_GT(y_offset, 0);
}

#if defined(OS_CHROMEOS)
// TODO(sanjeevr): http://crbug.com/79837
#define MAYBE_FindAndCopy DISABLED_FindAndCopy
#else
#define MAYBE_FindAndCopy FindAndCopy
#endif
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_FindAndCopy) {
  ASSERT_NO_FATAL_FAILURE(Load());
  // Verifies that find in page works.
  ASSERT_EQ(3, ui_test_utils::FindInPage(
      chrome::GetActiveTabContents(browser()), UTF8ToUTF16("adipiscing"),
      true, false, NULL));

  // Verify that copying selected text works.
  ui::Clipboard clipboard;
  // Reset the clipboard first.
  ui::Clipboard::ObjectMap objects;
  ui::Clipboard::ObjectMapParams params;
  params.push_back(std::vector<char>());
  objects[ui::Clipboard::CBF_TEXT] = params;
  clipboard.WriteObjects(ui::Clipboard::BUFFER_STANDARD, objects);

  chrome::GetActiveWebContents(browser())->GetRenderViewHost()->Copy();
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());

  std::string text;
  clipboard.ReadAsciiText(ui::Clipboard::BUFFER_STANDARD, &text);
  ASSERT_EQ("adipiscing", text);
}

// Tests that loading async pdfs works correctly (i.e. document fully loads).
// This also loads all documents that used to crash, to ensure we don't have
// regressions.
// If it flakes, reopen http://crbug.com/74548.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, SLOW_Loading) {
  ASSERT_TRUE(pdf_test_server()->Start());

  NavigationController* controller =
      &(chrome::GetActiveWebContents(browser())->GetController());
  content::NotificationRegistrar registrar;
  registrar.Add(this,
                content::NOTIFICATION_LOAD_STOP,
                content::Source<NavigationController>(controller));
  std::string base_url = std::string("files/");

  file_util::FileEnumerator file_enumerator(
      ui_test_utils::GetTestFilePath(GetPDFTestDir(), FilePath()),
      false,
      file_util::FileEnumerator::FILES,
      FILE_PATH_LITERAL("*.pdf"));
  for (FilePath file_path = file_enumerator.Next();
       !file_path.empty();
       file_path = file_enumerator.Next()) {
    std::string filename = file_path.BaseName().MaybeAsASCII();
    ASSERT_FALSE(filename.empty());

#if defined(OS_POSIX)
    if (filename == "sample.pdf")
      continue;  // Crashes on Mac and Linux.  http://crbug.com/63549
#endif

    LOG(WARNING) << "PDFBrowserTest.Loading: " << filename;

    GURL url = pdf_test_server()->GetURL(base_url + filename);
    ui_test_utils::NavigateToURL(browser(), url);

    while (true) {
      int last_count = load_stop_notification_count();
      // We might get extraneous chrome::LOAD_STOP notifications when
      // doing async loading.  This happens when the first loader is cancelled
      // and before creating a byte-range request loader.
      bool complete = false;
      ASSERT_TRUE(content::ExecuteJavaScriptAndExtractBool(
          chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
          std::wstring(),
          L"window.domAutomationController.send(plugin.documentLoadComplete())",
          &complete));
      if (complete)
        break;

      // Check if the LOAD_STOP notification could have come while we run a
      // nested message loop for the JS call.
      if (last_count != load_stop_notification_count())
        continue;
      content::WaitForLoadStop(chrome::GetActiveWebContents(browser()));
    }
  }
}

// Flaky as per http://crbug.com/74549.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, DISABLED_OnLoadAndReload) {
  ASSERT_TRUE(pdf_test_server()->Start());

  GURL url = pdf_test_server()->GetURL("files/onload_reload.html");
  ui_test_utils::NavigateToURL(browser(), url);

  content::WindowedNotificationObserver observer(
      content::NOTIFICATION_LOAD_STOP,
      content::Source<NavigationController>(
          &chrome::GetActiveWebContents(browser())->GetController()));
  ASSERT_TRUE(content::ExecuteJavaScript(
      chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
      std::wstring(),
      L"reloadPDF();"));
  observer.Wait();

  ASSERT_EQ("success",
            chrome::GetActiveWebContents(browser())->GetURL().query());
}

}  // namespace
<commit_msg>Try two different pixel results for mac for the PDFBrowserTest.Basic test.<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 "base/file_util.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/snapshot_tab_helper.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "net/test/test_server.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/screen.h"

using content::NavigationController;
using content::WebContents;

namespace {

// Include things like browser frame and scrollbar and make sure we're bigger
// than the test pdf document.
static const int kBrowserWidth = 1000;
static const int kBrowserHeight = 600;

class PDFBrowserTest : public InProcessBrowserTest,
                       public content::NotificationObserver {
 public:
  PDFBrowserTest()
      : snapshot_different_(true),
        next_dummy_search_value_(0),
        load_stop_notification_count_(0) {
    pdf_test_server_.reset(new net::TestServer(
        net::TestServer::TYPE_HTTP,
        net::TestServer::kLocalhost,
        FilePath(FILE_PATH_LITERAL("pdf/test"))));
  }

 protected:
  // Use our own TestServer so that we can serve files from the pdf directory.
  net::TestServer* pdf_test_server() { return pdf_test_server_.get(); }

  int load_stop_notification_count() const {
    return load_stop_notification_count_;
  }

  FilePath GetPDFTestDir() {
    return FilePath(FilePath::kCurrentDirectory).AppendASCII("..").
        AppendASCII("..").AppendASCII("..").AppendASCII("pdf").
        AppendASCII("test");
  }

  void Load() {
    // Make sure to set the window size before rendering, as otherwise rendering
    // to a smaller window and then expanding leads to slight anti-aliasing
    // differences of the text and the pixel comparison fails.
    gfx::Rect bounds(gfx::Rect(0, 0, kBrowserWidth, kBrowserHeight));
    gfx::Rect screen_bounds = gfx::Screen::GetPrimaryDisplay().bounds();
    ASSERT_GT(screen_bounds.width(), kBrowserWidth);
    ASSERT_GT(screen_bounds.height(), kBrowserHeight);
    browser()->window()->SetBounds(bounds);

    GURL url(ui_test_utils::GetTestUrl(
        GetPDFTestDir(),
        FilePath(FILE_PATH_LITERAL("pdf_browsertest.pdf"))));
    ui_test_utils::NavigateToURL(browser(), url);
  }

  bool VerifySnapshot(const std::string& expected_filename) {
    snapshot_different_ = true;
    expected_filename_ = expected_filename;
    TabContents* tab_contents =  chrome::GetActiveTabContents(browser());
    tab_contents->snapshot_tab_helper()->CaptureSnapshot();
    ui_test_utils::RegisterAndWait(
        this,
        chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN,
        content::Source<WebContents>(tab_contents->web_contents()));
    if (snapshot_different_) {
      LOG(INFO) << "Rendering didn't match, see result " <<
          snapshot_filename_.value().c_str();
    }
    return !snapshot_different_;
  }

  void WaitForResponse() {
    // Even if the plugin has loaded the data or scrolled, because of how
    // pepper painting works, we might not have the data.  One way to force this
    // to be flushed is to do a find operation, since on this two-page test
    // document, it'll wait for us to flush the renderer message loop twice and
    // also the browser's once, at which point we're guaranteed to have updated
    // the backingstore.  Hacky, but it works.
    // Note that we need to change the text each time, because if we don't the
    // renderer code will think the second message is to go to next result, but
    // there are none so the plugin will assert.

    string16 query = UTF8ToUTF16(
        std::string("xyzxyz" + base::IntToString(next_dummy_search_value_++)));
    ASSERT_EQ(0, ui_test_utils::FindInPage(
        chrome::GetActiveTabContents(browser()), query, true, false, NULL));
  }

 private:
  // content::NotificationObserver
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) {
    if (type == chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN) {
      MessageLoopForUI::current()->Quit();
      FilePath reference = ui_test_utils::GetTestFilePath(
          GetPDFTestDir(),
          FilePath().AppendASCII(expected_filename_));
      base::PlatformFileInfo info;
      ASSERT_TRUE(file_util::GetFileInfo(reference, &info));
      int size = static_cast<size_t>(info.size);
      scoped_array<char> data(new char[size]);
      ASSERT_EQ(size, file_util::ReadFile(reference, data.get(), size));

      int w, h;
      std::vector<unsigned char> decoded;
      ASSERT_TRUE(gfx::PNGCodec::Decode(
          reinterpret_cast<unsigned char*>(data.get()), size,
          gfx::PNGCodec::FORMAT_BGRA, &decoded, &w, &h));
      int32* ref_pixels = reinterpret_cast<int32*>(&decoded[0]);

      const SkBitmap* bitmap = content::Details<const SkBitmap>(details).ptr();
      int32* pixels = static_cast<int32*>(bitmap->getPixels());

      // Get the background color, and use it to figure out the x-offsets in
      // each image.  The reason is that depending on the theme in the OS, the
      // same browser width can lead to slightly different plugin sizes, so the
      // pdf content will start at different x offsets.
      // Also note that the images we saved are cut off before the scrollbar, as
      // that'll change depending on the theme, and also cut off vertically so
      // that the ui controls don't show up, as those fade-in and so the timing
      // will affect their transparency.
      int32 bg_color = ref_pixels[0];
      int ref_x_offset, snapshot_x_offset;
      for (ref_x_offset = 0; ref_x_offset < w; ++ref_x_offset) {
        if (ref_pixels[ref_x_offset] != bg_color)
          break;
      }

      for (snapshot_x_offset = 0; snapshot_x_offset < bitmap->width();
           ++snapshot_x_offset) {
        if (pixels[snapshot_x_offset] != bg_color)
          break;
      }

      int x_max = std::min(
          w - ref_x_offset, bitmap->width() - snapshot_x_offset);
      int y_max = std::min(h, bitmap->height());
      int stride = bitmap->rowBytes();
      snapshot_different_ = false;
      for (int y = 0; y < y_max && !snapshot_different_; ++y) {
        for (int x = 0; x < x_max && !snapshot_different_; ++x) {
          if (pixels[y * stride / sizeof(int32) + x + snapshot_x_offset] !=
              ref_pixels[y * w + x + ref_x_offset])
            snapshot_different_ = true;
        }
      }

      if (snapshot_different_) {
        std::vector<unsigned char> png_data;
        gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &png_data);
        if (file_util::CreateTemporaryFile(&snapshot_filename_)) {
          file_util::WriteFile(snapshot_filename_,
              reinterpret_cast<char*>(&png_data[0]), png_data.size());
        }
      }
    } else if (type == content::NOTIFICATION_LOAD_STOP) {
      load_stop_notification_count_++;
    }
  }

  // True if the snapshot differed from the expected value.
  bool snapshot_different_;
  // Internal variable used to synchronize to the renderer.
  int next_dummy_search_value_;
  // The filename of the bitmap to compare the snapshot to.
  std::string expected_filename_;
  // If the snapshot is different, holds the location where it's saved.
  FilePath snapshot_filename_;
  // How many times we've seen chrome::LOAD_STOP.
  int load_stop_notification_count_;

  scoped_ptr<net::TestServer> pdf_test_server_;
};

#if defined(OS_CHROMEOS)
// TODO(sanjeevr): http://crbug.com/79837
#define MAYBE_Basic DISABLED_Basic
#else
#define MAYBE_Basic Basic
#endif
// Tests basic PDF rendering.  This can be broken depending on bad merges with
// the vendor, so it's important that we have basic sanity checking.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Basic) {
  ASSERT_NO_FATAL_FAILURE(Load());
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());
  // OS X uses CoreText, and FreeType renders slightly different on Linux and
  // Win.
#if defined(OS_MACOSX)
  // The bots render differently than locally, see http://crbug.com/142531.
  ASSERT_TRUE(VerifySnapshot("pdf_browsertest_mac.png") ||
              VerifySnapshot("pdf_browsertest_mac2.png"));
#elif defined(OS_LINUX)
  ASSERT_TRUE(VerifySnapshot("pdf_browsertest_linux.png"));
#else
  ASSERT_TRUE(VerifySnapshot("pdf_browsertest.png"));
#endif
}

#if defined(OS_CHROMEOS)
// TODO(sanjeevr): http://crbug.com/79837
#define MAYBE_Scroll DISABLED_Scroll
#else
#define MAYBE_Scroll Scroll
#endif
// Tests that scrolling works.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Scroll) {
  ASSERT_NO_FATAL_FAILURE(Load());

  // We use wheel mouse event since that's the only one we can easily push to
  // the renderer.  There's no way to push a cross-platform keyboard event at
  // the moment.
  WebKit::WebMouseWheelEvent wheel_event;
  wheel_event.type = WebKit::WebInputEvent::MouseWheel;
  wheel_event.deltaY = -200;
  wheel_event.wheelTicksY = -2;
  WebContents* web_contents = chrome::GetActiveWebContents(browser());
  web_contents->GetRenderViewHost()->ForwardWheelEvent(wheel_event);
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());

  int y_offset = 0;
  ASSERT_TRUE(content::ExecuteJavaScriptAndExtractInt(
      chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
      std::wstring(),
      L"window.domAutomationController.send(plugin.pageYOffset())",
      &y_offset));
  ASSERT_GT(y_offset, 0);
}

#if defined(OS_CHROMEOS)
// TODO(sanjeevr): http://crbug.com/79837
#define MAYBE_FindAndCopy DISABLED_FindAndCopy
#else
#define MAYBE_FindAndCopy FindAndCopy
#endif
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_FindAndCopy) {
  ASSERT_NO_FATAL_FAILURE(Load());
  // Verifies that find in page works.
  ASSERT_EQ(3, ui_test_utils::FindInPage(
      chrome::GetActiveTabContents(browser()), UTF8ToUTF16("adipiscing"),
      true, false, NULL));

  // Verify that copying selected text works.
  ui::Clipboard clipboard;
  // Reset the clipboard first.
  ui::Clipboard::ObjectMap objects;
  ui::Clipboard::ObjectMapParams params;
  params.push_back(std::vector<char>());
  objects[ui::Clipboard::CBF_TEXT] = params;
  clipboard.WriteObjects(ui::Clipboard::BUFFER_STANDARD, objects);

  chrome::GetActiveWebContents(browser())->GetRenderViewHost()->Copy();
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());

  std::string text;
  clipboard.ReadAsciiText(ui::Clipboard::BUFFER_STANDARD, &text);
  ASSERT_EQ("adipiscing", text);
}

// Tests that loading async pdfs works correctly (i.e. document fully loads).
// This also loads all documents that used to crash, to ensure we don't have
// regressions.
// If it flakes, reopen http://crbug.com/74548.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, SLOW_Loading) {
  ASSERT_TRUE(pdf_test_server()->Start());

  NavigationController* controller =
      &(chrome::GetActiveWebContents(browser())->GetController());
  content::NotificationRegistrar registrar;
  registrar.Add(this,
                content::NOTIFICATION_LOAD_STOP,
                content::Source<NavigationController>(controller));
  std::string base_url = std::string("files/");

  file_util::FileEnumerator file_enumerator(
      ui_test_utils::GetTestFilePath(GetPDFTestDir(), FilePath()),
      false,
      file_util::FileEnumerator::FILES,
      FILE_PATH_LITERAL("*.pdf"));
  for (FilePath file_path = file_enumerator.Next();
       !file_path.empty();
       file_path = file_enumerator.Next()) {
    std::string filename = file_path.BaseName().MaybeAsASCII();
    ASSERT_FALSE(filename.empty());

#if defined(OS_POSIX)
    if (filename == "sample.pdf")
      continue;  // Crashes on Mac and Linux.  http://crbug.com/63549
#endif

    LOG(WARNING) << "PDFBrowserTest.Loading: " << filename;

    GURL url = pdf_test_server()->GetURL(base_url + filename);
    ui_test_utils::NavigateToURL(browser(), url);

    while (true) {
      int last_count = load_stop_notification_count();
      // We might get extraneous chrome::LOAD_STOP notifications when
      // doing async loading.  This happens when the first loader is cancelled
      // and before creating a byte-range request loader.
      bool complete = false;
      ASSERT_TRUE(content::ExecuteJavaScriptAndExtractBool(
          chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
          std::wstring(),
          L"window.domAutomationController.send(plugin.documentLoadComplete())",
          &complete));
      if (complete)
        break;

      // Check if the LOAD_STOP notification could have come while we run a
      // nested message loop for the JS call.
      if (last_count != load_stop_notification_count())
        continue;
      content::WaitForLoadStop(chrome::GetActiveWebContents(browser()));
    }
  }
}

// Flaky as per http://crbug.com/74549.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, DISABLED_OnLoadAndReload) {
  ASSERT_TRUE(pdf_test_server()->Start());

  GURL url = pdf_test_server()->GetURL("files/onload_reload.html");
  ui_test_utils::NavigateToURL(browser(), url);

  content::WindowedNotificationObserver observer(
      content::NOTIFICATION_LOAD_STOP,
      content::Source<NavigationController>(
          &chrome::GetActiveWebContents(browser())->GetController()));
  ASSERT_TRUE(content::ExecuteJavaScript(
      chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
      std::wstring(),
      L"reloadPDF();"));
  observer.Wait();

  ASSERT_EQ("success",
            chrome::GetActiveWebContents(browser())->GetURL().query());
}

}  // namespace
<|endoftext|>


<commit_before>//
//  segmentizer.h
//  ndnrtc
//
//  Copyright 2013 Regents of the University of California
//  For licensing details see the LICENSE file.
//
//  Author:  Peter Gusev
//

#include <iostream>
#include "fec.h"

using namespace fec;

//******************************************************************************
#pragma mark - construction/destruction
Rs28Encoder::Rs28Encoder(unsigned int nSourceSymbols,
                         unsigned int nRepairSymbols,
                         unsigned int symbolLength):
Rs28Coder(nSourceSymbols, nRepairSymbols, symbolLength)
{
}

int
Rs28Encoder::encode(unsigned char* data, unsigned char* parityData)
{
    initCoder();

    if (!Rs28Coder<OF_ENCODER>::isCoderReady_)
        return -1;

    int ret = 0;
    unsigned char** encodingSymbolTable = buildSymbolTable(data, parityData);
    of_parameters_t* params = Rs28Coder<OF_ENCODER>::coderParameters_;
    of_session_t* session = Rs28Coder<OF_ENCODER>::coderSession_;

    for (UINT32 esi = params->nb_source_symbols;
         esi < params->nb_source_symbols + params->nb_repair_symbols && ret >= 0;
         esi++)
    {
				memset(encodingSymbolTable[esi], 0, params->encoding_symbol_length);

				if (of_build_repair_symbol(session, (void**)encodingSymbolTable, esi) != OF_STATUS_OK)
				{
            ret = -1;
				}
    }

    releaseSymbolTable(encodingSymbolTable);

    return ret;
}

//******************************************************************************
#pragma mark - construction/destruction
Rs28Decoder::Rs28Decoder(unsigned int nSourceSymbols,
                         unsigned int nRepairSymbols,
                         unsigned int symbolLength):
Rs28Coder(nSourceSymbols, nRepairSymbols, symbolLength)
{
}

int
Rs28Decoder::decode(unsigned char* data, unsigned char* parityData,
                    unsigned char* rList)
{
    initCoder();

    if (!Rs28Coder<OF_DECODER>::isCoderReady_)
        return -1;

    int ret = 0;
    unsigned char** decodingSymbolTable = buildSymbolTable(data, parityData, rList);
    of_session_t* session = Rs28Coder<OF_DECODER>::coderSession_;

    for (unsigned int i = 0; i < nSourceSymbols_+nRepairSymbols_; i++)
    {
        if (rList[i] == FEC_RLIST_SYMREADY)
            of_decode_with_new_symbol(session, decodingSymbolTable[i], i);
        else
            rList[i] = FEC_RLIST_SYMREPAIRED;
    }

    if (of_finish_decoding(coderSession_) != OF_STATUS_OK)
        ret = -1;
    else
    {
        if(of_get_source_symbols_tab(session, (void**)decodingSymbolTable) != OF_STATUS_OK)
            ret = -1;
        else
        {
            for (int i = 0; i < nSourceSymbols_+nRepairSymbols_; i++)
                if (rList[i] == FEC_RLIST_SYMREPAIRED)
                {
                    ret++;
                    if (i < nSourceSymbols_)
                        memcpy(&data[i*symbolLength_], decodingSymbolTable[i], symbolLength_);
                    else
                        memcpy(&parityData[(i-nSourceSymbols_)*symbolLength_], decodingSymbolTable[i], symbolLength_);
                }
        }
    }

    releaseSymbolTable(decodingSymbolTable);

    return ret;
}
<commit_msg>[untracked] fixed crash caused by FEC code<commit_after>//
//  segmentizer.h
//  ndnrtc
//
//  Copyright 2013 Regents of the University of California
//  For licensing details see the LICENSE file.
//
//  Author:  Peter Gusev
//

#include <iostream>
#include "fec.h"

using namespace fec;

//******************************************************************************
#pragma mark - construction/destruction
Rs28Encoder::Rs28Encoder(unsigned int nSourceSymbols,
                         unsigned int nRepairSymbols,
                         unsigned int symbolLength):
Rs28Coder(nSourceSymbols, nRepairSymbols, symbolLength)
{
}

int
Rs28Encoder::encode(unsigned char* data, unsigned char* parityData)
{
    initCoder();

    if (!Rs28Coder<OF_ENCODER>::isCoderReady_)
        return -1;

    int ret = 0;
    unsigned char** encodingSymbolTable = buildSymbolTable(data, parityData);
    of_parameters_t* params = Rs28Coder<OF_ENCODER>::coderParameters_;
    of_session_t* session = Rs28Coder<OF_ENCODER>::coderSession_;

    for (UINT32 esi = params->nb_source_symbols;
         esi < params->nb_source_symbols + params->nb_repair_symbols && ret >= 0;
         esi++)
    {
				memset(encodingSymbolTable[esi], 0, params->encoding_symbol_length);

				if (of_build_repair_symbol(session, (void**)encodingSymbolTable, esi) != OF_STATUS_OK)
				{
            ret = -1;
				}
    }

    releaseSymbolTable(encodingSymbolTable);

    return ret;
}

//******************************************************************************
#pragma mark - construction/destruction
Rs28Decoder::Rs28Decoder(unsigned int nSourceSymbols,
                         unsigned int nRepairSymbols,
                         unsigned int symbolLength):
Rs28Coder(nSourceSymbols, nRepairSymbols, symbolLength)
{
}

int
Rs28Decoder::decode(unsigned char* data, unsigned char* parityData,
                    unsigned char* rList)
{
    initCoder();

    if (!Rs28Coder<OF_DECODER>::isCoderReady_)
        return -1;

    int ret = 0;
    unsigned char** decodingSymbolTable = buildSymbolTable(data, parityData, rList);
    of_session_t* session = Rs28Coder<OF_DECODER>::coderSession_;

    for (unsigned int i = 0; i < nSourceSymbols_+nRepairSymbols_; i++)
    {
        if (rList[i] == FEC_RLIST_SYMREADY)
            of_decode_with_new_symbol(session, decodingSymbolTable[i], i);
        else
            rList[i] = FEC_RLIST_SYMREPAIRED;
    }

    if (of_finish_decoding(coderSession_) != OF_STATUS_OK)
        ret = -1;
    else
    {
        if(of_get_source_symbols_tab(session, (void**)decodingSymbolTable) != OF_STATUS_OK)
            ret = -1;
        else
        {
            for (int i = 0; i < nSourceSymbols_+nRepairSymbols_; i++)
                if (rList[i] == FEC_RLIST_SYMREPAIRED)
                {
                    ret++;
                    if (i < nSourceSymbols_)
                        memcpy(&data[i*symbolLength_], decodingSymbolTable[i], symbolLength_);
                }
        }
    }

    releaseSymbolTable(decodingSymbolTable);

    return ret;
}
<|endoftext|>


<commit_before>#include "GaitRecorder.hh"

using std::string;
using std::cout;

namespace gazebo{
PoseRecord::PoseRecord()
{
  for (int i = 0; i < 4; ++i) {
    JointAngles[i] = 0;
  }
} // PoseRecord::PoseRecord
PoseRecord::PoseRecord(double joint0, double joint1, double joint2,
    double joint3, math::Pose pos)
{
  JointAngles[0] = joint0;
  JointAngles[1] = joint1;
  JointAngles[2] = joint2;
  JointAngles[3] = joint3;
  Position = pos;
} // PoseRecord::PoseRecord
void PoseRecord::UpdateJoints(double joint0, double joint1, double joint2,
    double joint3, math::Pose pos)
{
  JointAngles[0] = joint0;
  JointAngles[1] = joint1;
  JointAngles[2] = joint2;
  JointAngles[3] = joint3;
  Position = pos;
} // PoseRecord::UpdateJoints

Frame::Frame(string frame_name)
{
  frameName = frame_name;
} // Frame::Frame
void Frame::AddAPosition(PoseRecord pos_rec)
{
  modulePositions.push_back(pos_rec);
} // Frame::AddAPosition
unsigned int Frame::GetPositionSize(void) const
{
  return modulePositions.size();
}
PoseRecord Frame::GetPosition(unsigned int idx) const
{
  return modulePositions.at(idx);
}

GaitRecorder::GaitRecorder()
    :WorldServer()
{} // GaitRecorder::GaitRecorder
GaitRecorder::~GaitRecorder(){}
void GaitRecorder::ExtraInitializationInLoad(physics::WorldPtr _parent,
      sdf::ElementPtr _sdf)
{
  transport::NodePtr node_gait(new transport::Node());
  node_gait->Init("GaitRecorder");
  string topic_name = "~/gaitSubscriber";
  this->gaitInfoSub = node_gait->Subscribe(
      topic_name,&GaitRecorder::GaitRecorderMessageDecoding, this);
  cout<<"World: subscriber topic: "<<this->gaitInfoSub->GetTopic()<<endl;

  // // Build initial configuration from file
  // BuildConfigurationFromXML(INTIALCONFIGURATION);
} // GaitRecorder::ExtraInitializationInLoad
void GaitRecorder::ExtraWorkWhenModelInserted(CommandMessagePtr &msg)
{
  if (GetInitialJointSequenceSize() == 1) {
    string new_frame_name = "frame0";
    Frame new_frame(new_frame_name);
    RecordCurrentPose(new_frame);
    frames.push_back(new_frame);
  }
} // GaitRecorder::ExtraWorkWhenModelInserted
void GaitRecorder::GaitRecorderMessageDecoding(GaitRecMessagePtr &msg)
{
  string modelname = msg->modelname();
  bool begin_a_new_frame = msg->newframe();
  bool play_mode = msg->playstatus();
  if (begin_a_new_frame) {
    string new_frame_name = "frame"+util::to_string((int)frames.size());
    Frame new_frame(new_frame_name);
    RecordCurrentPose(new_frame);
    frames.push_back(new_frame);
    return;
  }
  // Reset the position
  if (msg->has_resetflag()) {
    // Reset the robot position
    if (msg->resetflag()) {
      SetPose(&frames.back());
    }
  }else{
    bool load_Configuration = false;
    if (msg->has_loadconfiguration()) {
      load_Configuration = msg->loadconfiguration();
    }
    if (load_Configuration) {
      // Build initial configuration from file
      BuildConfigurationFromXML(msg->extrinfo());
    }else{
      // Sending gait table commands
      if (play_mode) {
        // Disconnect Two Model
        if (msg->has_extrinfo()) {
          string extrainfo = msg->extrinfo();
          if (extrainfo.substr(2,1).compare("+")==0 ||
              extrainfo.substr(2,1).compare("-")==0) {
            bool connect = true;
            if (extrainfo.substr(2,1).compare("-")==0) {
              connect = false;
            }
            extrainfo = extrainfo.substr(4);
            string modulename1 = extrainfo.substr(1,extrainfo.find(" ")-1);
            extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
            int node1;
            int node2;
            string modulename2;
            if (extrainfo.substr(0,1).compare("&") == 0) {
              modulename2 = extrainfo.substr(1,extrainfo.find(" ")-1);
            }else{
              node1 = atoi(extrainfo.substr(1,extrainfo.find(" ")-1).c_str());
              extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
              modulename2 = extrainfo.substr(1,extrainfo.find(" ")-1);
              extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
              node2 = atoi(extrainfo.substr(1,extrainfo.find(" ")-1).c_str());
            }
            string condition = msg->condition();
            string dependency = msg->dependency();
            if (connect) {
              SendGaitTable(GetModulePtrByName(modulename1), modulename1,
                  modulename2, node1, node2, 1,condition,dependency);
            }else{
              SendGaitTable(GetModulePtrByName(modulename1), modulename1,
                  modulename2, 4, 4, 2,condition,dependency);
            }
            return;
          }
        }
        bool flags[4] = {true,true,true,true};
        double joints_values[4] = {0,0,0,0};
        joints_values[0] = msg->jointangles(0);
        joints_values[1] = msg->jointangles(1);
        joints_values[2] = msg->jointangles(2);
        joints_values[3] = msg->jointangles(3);
        string condition = msg->condition();
        string dependency = msg->dependency();
        unsigned int time_interval = msg->timer();
        if (time_interval == 0) {
          SendGaitTable(GetModulePtrByName(modelname), flags, joints_values, 3,
              condition, dependency);
        }else{
          SendGaitTable(GetModulePtrByName(modelname), flags, joints_values, 3,
              time_interval, condition, dependency);
        }
      }
      // User specify a joint angle
      if (!play_mode) {
        // Disconnect Two Model
        // TODO: Need an elegent way to deal with none play mode disconnection
        if (msg->has_extrinfo()) {
          string extrainfo = msg->extrinfo();
          if (extrainfo.substr(2,1).compare("+")==0 ||
              extrainfo.substr(2,1).compare("-")==0) {
            bool connect = true;
            if (extrainfo.substr(2,1).compare("-")==0) {
              connect = false;
            }
            extrainfo = extrainfo.substr(4);
            string modulename1 = extrainfo.substr(1,extrainfo.find(" ")-1);
            extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
            int node1;
            int node2;
            string modulename2;
            if (extrainfo.substr(0,1).compare("&") == 0) {
              modulename2 = extrainfo.substr(1,extrainfo.find(" ")-1);
            }else{
              node1 = atoi(extrainfo.substr(1,extrainfo.find(" ")-1).c_str());
              extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
              modulename2 = extrainfo.substr(1,extrainfo.find(" ")-1);
              extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
              node2 = atoi(extrainfo.substr(1,extrainfo.find(" ")-1).c_str());
            }

            if (connect) {
              ActiveConnect(GetModulePtrByName(modulename1),
                  GetModulePtrByName(modulename2), node1, node2);
            }else{
              Disconnect(modulename1, modulename2);
            }
            return;
          }
        }
        bool flags[4] = {true,true,true,true};
        double joints_values[4] = {0,0,0,0};
        joints_values[0] = msg->jointangles(0);
        joints_values[1] = msg->jointangles(1);
        joints_values[2] = msg->jointangles(2);
        joints_values[3] = msg->jointangles(3);
        SendGaitTableInstance(GetModulePtrByName(modelname), flags, joints_values,3);
        cout<<"World: model problem: "<<modelname<<endl;
        currentWorld->GetModel(modelname)->GetJoint("Front_wheel_hinge")
            ->SetAngle(0,msg->jointangles(0));
        currentWorld->GetModel(modelname)->GetJoint("Left_wheel_hinge")
            ->SetAngle(0,msg->jointangles(1));
        currentWorld->GetModel(modelname)->GetJoint("Right_wheel_hinge")
            ->SetAngle(0,msg->jointangles(2));
        currentWorld->GetModel(modelname)->GetJoint("Center_hinge")
            ->SetAngle(0,msg->jointangles(3));
      }
    }
  }
} // GaitRecorder::GaitRecorderMessageDecoding
void GaitRecorder::RecordCurrentPose(Frame &current_frame)
{
  for (unsigned int i = 0; i < GetModuleListSize(); ++i) {
    double joint0 = GetModulePtrByIDX(i)->ModuleObject->GetJoint("Front_wheel_hinge")
        ->GetAngle(0).Radian();
    double joint1 = GetModulePtrByIDX(i)->ModuleObject->GetJoint("Left_wheel_hinge")
        ->GetAngle(0).Radian();
    double joint2 = GetModulePtrByIDX(i)->ModuleObject->GetJoint("Right_wheel_hinge")
        ->GetAngle(0).Radian();
    double joint3 = GetModulePtrByIDX(i)->ModuleObject->GetJoint("Center_hinge")
        ->GetAngle(0).Radian();
    math::Pose currentmodel = GetModulePtrByIDX(i)->ModuleObject->GetWorldPose();
    PoseRecord new_record(joint0,joint1,joint2,joint3,currentmodel);
    current_frame.AddAPosition(new_record);
  }
} // GaitRecorder::RecordCurrentPose
void GaitRecorder::SetPose(const Frame *a_frame)
{
  this->currentWorld->DisableAllModels();
  // common::Time::MSleep(1000);
  for (unsigned int i = 0; i < a_frame->GetPositionSize(); ++i) {
    bool flags[4] = {true,true,true,true};
    SendGaitTableInstance(
        GetModulePtrByIDX(i), flags, a_frame->GetPosition(i).JointAngles, 3);
    GetModulePtrByIDX(i)->ModuleObject->GetJoint("Front_wheel_hinge")->SetAngle(
        0,a_frame->GetPosition(i).JointAngles[0]);
    GetModulePtrByIDX(i)->ModuleObject->GetJoint("Left_wheel_hinge")->SetAngle(
        0,a_frame->GetPosition(i).JointAngles[1]);
    GetModulePtrByIDX(i)->ModuleObject->GetJoint("Right_wheel_hinge")->SetAngle(
        0,a_frame->GetPosition(i).JointAngles[2]);
    GetModulePtrByIDX(i)->ModuleObject->GetJoint("Center_hinge")->SetAngle(
        0,a_frame->GetPosition(i).JointAngles[3]);
    GetModulePtrByIDX(i)->ModuleObject->SetWorldPose(a_frame->GetPosition(i).Position);
  }
  this->currentWorld->EnableAllModels();
  // common::Time::MSleep(5000);
  // this->currentWorld->EnablePhysicsEngine(true);
} // GaitRecorder::SetPose
// Register this plugin with the simulator
GZ_REGISTER_WORLD_PLUGIN(GaitRecorder)
} // namespace gazebo<commit_msg>Fixed the namespace bug in the gait recorder worldplugin<commit_after>#include "GaitRecorder.hh"

using std::string;
using std::cout;
using util::to_string;

namespace gazebo{
PoseRecord::PoseRecord()
{
  for (int i = 0; i < 4; ++i) {
    JointAngles[i] = 0;
  }
} // PoseRecord::PoseRecord
PoseRecord::PoseRecord(double joint0, double joint1, double joint2,
    double joint3, math::Pose pos)
{
  JointAngles[0] = joint0;
  JointAngles[1] = joint1;
  JointAngles[2] = joint2;
  JointAngles[3] = joint3;
  Position = pos;
} // PoseRecord::PoseRecord
void PoseRecord::UpdateJoints(double joint0, double joint1, double joint2,
    double joint3, math::Pose pos)
{
  JointAngles[0] = joint0;
  JointAngles[1] = joint1;
  JointAngles[2] = joint2;
  JointAngles[3] = joint3;
  Position = pos;
} // PoseRecord::UpdateJoints

Frame::Frame(string frame_name)
{
  frameName = frame_name;
} // Frame::Frame
void Frame::AddAPosition(PoseRecord pos_rec)
{
  modulePositions.push_back(pos_rec);
} // Frame::AddAPosition
unsigned int Frame::GetPositionSize(void) const
{
  return modulePositions.size();
}
PoseRecord Frame::GetPosition(unsigned int idx) const
{
  return modulePositions.at(idx);
}

GaitRecorder::GaitRecorder()
    :WorldServer()
{} // GaitRecorder::GaitRecorder
GaitRecorder::~GaitRecorder(){}
void GaitRecorder::ExtraInitializationInLoad(physics::WorldPtr _parent,
      sdf::ElementPtr _sdf)
{
  transport::NodePtr node_gait(new transport::Node());
  node_gait->Init("GaitRecorder");
  string topic_name = "~/gaitSubscriber";
  this->gaitInfoSub = node_gait->Subscribe(
      topic_name,&GaitRecorder::GaitRecorderMessageDecoding, this);
  cout<<"World: subscriber topic: "<<this->gaitInfoSub->GetTopic()<<endl;

  // // Build initial configuration from file
  // BuildConfigurationFromXML(INTIALCONFIGURATION);
} // GaitRecorder::ExtraInitializationInLoad
void GaitRecorder::ExtraWorkWhenModelInserted(CommandMessagePtr &msg)
{
  if (GetInitialJointSequenceSize() == 1) {
    string new_frame_name = "frame0";
    Frame new_frame(new_frame_name);
    RecordCurrentPose(new_frame);
    frames.push_back(new_frame);
  }
} // GaitRecorder::ExtraWorkWhenModelInserted
void GaitRecorder::GaitRecorderMessageDecoding(GaitRecMessagePtr &msg)
{
  string modelname = msg->modelname();
  bool begin_a_new_frame = msg->newframe();
  bool play_mode = msg->playstatus();
  if (begin_a_new_frame) {
    string new_frame_name = "frame"+to_string((int)frames.size());
    Frame new_frame(new_frame_name);
    RecordCurrentPose(new_frame);
    frames.push_back(new_frame);
    return;
  }
  // Reset the position
  if (msg->has_resetflag()) {
    // Reset the robot position
    if (msg->resetflag()) {
      SetPose(&frames.back());
    }
  }else{
    bool load_Configuration = false;
    if (msg->has_loadconfiguration()) {
      load_Configuration = msg->loadconfiguration();
    }
    if (load_Configuration) {
      // Build initial configuration from file
      BuildConfigurationFromXML(msg->extrinfo());
    }else{
      // Sending gait table commands
      if (play_mode) {
        // Disconnect Two Model
        if (msg->has_extrinfo()) {
          string extrainfo = msg->extrinfo();
          if (extrainfo.substr(2,1).compare("+")==0 ||
              extrainfo.substr(2,1).compare("-")==0) {
            bool connect = true;
            if (extrainfo.substr(2,1).compare("-")==0) {
              connect = false;
            }
            extrainfo = extrainfo.substr(4);
            string modulename1 = extrainfo.substr(1,extrainfo.find(" ")-1);
            extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
            int node1;
            int node2;
            string modulename2;
            if (extrainfo.substr(0,1).compare("&") == 0) {
              modulename2 = extrainfo.substr(1,extrainfo.find(" ")-1);
            }else{
              node1 = atoi(extrainfo.substr(1,extrainfo.find(" ")-1).c_str());
              extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
              modulename2 = extrainfo.substr(1,extrainfo.find(" ")-1);
              extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
              node2 = atoi(extrainfo.substr(1,extrainfo.find(" ")-1).c_str());
            }
            string condition = msg->condition();
            string dependency = msg->dependency();
            if (connect) {
              SendGaitTable(GetModulePtrByName(modulename1), modulename1,
                  modulename2, node1, node2, 1,condition,dependency);
            }else{
              SendGaitTable(GetModulePtrByName(modulename1), modulename1,
                  modulename2, 4, 4, 2,condition,dependency);
            }
            return;
          }
        }
        bool flags[4] = {true,true,true,true};
        double joints_values[4] = {0,0,0,0};
        joints_values[0] = msg->jointangles(0);
        joints_values[1] = msg->jointangles(1);
        joints_values[2] = msg->jointangles(2);
        joints_values[3] = msg->jointangles(3);
        string condition = msg->condition();
        string dependency = msg->dependency();
        unsigned int time_interval = msg->timer();
        if (time_interval == 0) {
          SendGaitTable(GetModulePtrByName(modelname), flags, joints_values, 3,
              condition, dependency);
        }else{
          SendGaitTable(GetModulePtrByName(modelname), flags, joints_values, 3,
              time_interval, condition, dependency);
        }
      }
      // User specify a joint angle
      if (!play_mode) {
        // Disconnect Two Model
        // TODO: Need an elegent way to deal with none play mode disconnection
        if (msg->has_extrinfo()) {
          string extrainfo = msg->extrinfo();
          if (extrainfo.substr(2,1).compare("+")==0 ||
              extrainfo.substr(2,1).compare("-")==0) {
            bool connect = true;
            if (extrainfo.substr(2,1).compare("-")==0) {
              connect = false;
            }
            extrainfo = extrainfo.substr(4);
            string modulename1 = extrainfo.substr(1,extrainfo.find(" ")-1);
            extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
            int node1;
            int node2;
            string modulename2;
            if (extrainfo.substr(0,1).compare("&") == 0) {
              modulename2 = extrainfo.substr(1,extrainfo.find(" ")-1);
            }else{
              node1 = atoi(extrainfo.substr(1,extrainfo.find(" ")-1).c_str());
              extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
              modulename2 = extrainfo.substr(1,extrainfo.find(" ")-1);
              extrainfo = extrainfo.substr(extrainfo.find(" ")+1);
              node2 = atoi(extrainfo.substr(1,extrainfo.find(" ")-1).c_str());
            }

            if (connect) {
              ActiveConnect(GetModulePtrByName(modulename1),
                  GetModulePtrByName(modulename2), node1, node2);
            }else{
              Disconnect(modulename1, modulename2);
            }
            return;
          }
        }
        bool flags[4] = {true,true,true,true};
        double joints_values[4] = {0,0,0,0};
        joints_values[0] = msg->jointangles(0);
        joints_values[1] = msg->jointangles(1);
        joints_values[2] = msg->jointangles(2);
        joints_values[3] = msg->jointangles(3);
        SendGaitTableInstance(GetModulePtrByName(modelname), flags, joints_values,3);
        cout<<"World: model problem: "<<modelname<<endl;
        currentWorld->GetModel(modelname)->GetJoint("Front_wheel_hinge")
            ->SetAngle(0,msg->jointangles(0));
        currentWorld->GetModel(modelname)->GetJoint("Left_wheel_hinge")
            ->SetAngle(0,msg->jointangles(1));
        currentWorld->GetModel(modelname)->GetJoint("Right_wheel_hinge")
            ->SetAngle(0,msg->jointangles(2));
        currentWorld->GetModel(modelname)->GetJoint("Center_hinge")
            ->SetAngle(0,msg->jointangles(3));
      }
    }
  }
} // GaitRecorder::GaitRecorderMessageDecoding
void GaitRecorder::RecordCurrentPose(Frame &current_frame)
{
  for (unsigned int i = 0; i < GetModuleListSize(); ++i) {
    double joint0 = GetModulePtrByIDX(i)->ModuleObject->GetJoint("Front_wheel_hinge")
        ->GetAngle(0).Radian();
    double joint1 = GetModulePtrByIDX(i)->ModuleObject->GetJoint("Left_wheel_hinge")
        ->GetAngle(0).Radian();
    double joint2 = GetModulePtrByIDX(i)->ModuleObject->GetJoint("Right_wheel_hinge")
        ->GetAngle(0).Radian();
    double joint3 = GetModulePtrByIDX(i)->ModuleObject->GetJoint("Center_hinge")
        ->GetAngle(0).Radian();
    math::Pose currentmodel = GetModulePtrByIDX(i)->ModuleObject->GetWorldPose();
    PoseRecord new_record(joint0,joint1,joint2,joint3,currentmodel);
    current_frame.AddAPosition(new_record);
  }
} // GaitRecorder::RecordCurrentPose
void GaitRecorder::SetPose(const Frame *a_frame)
{
  this->currentWorld->DisableAllModels();
  // common::Time::MSleep(1000);
  for (unsigned int i = 0; i < a_frame->GetPositionSize(); ++i) {
    bool flags[4] = {true,true,true,true};
    SendGaitTableInstance(
        GetModulePtrByIDX(i), flags, a_frame->GetPosition(i).JointAngles, 3);
    GetModulePtrByIDX(i)->ModuleObject->GetJoint("Front_wheel_hinge")->SetAngle(
        0,a_frame->GetPosition(i).JointAngles[0]);
    GetModulePtrByIDX(i)->ModuleObject->GetJoint("Left_wheel_hinge")->SetAngle(
        0,a_frame->GetPosition(i).JointAngles[1]);
    GetModulePtrByIDX(i)->ModuleObject->GetJoint("Right_wheel_hinge")->SetAngle(
        0,a_frame->GetPosition(i).JointAngles[2]);
    GetModulePtrByIDX(i)->ModuleObject->GetJoint("Center_hinge")->SetAngle(
        0,a_frame->GetPosition(i).JointAngles[3]);
    GetModulePtrByIDX(i)->ModuleObject->SetWorldPose(a_frame->GetPosition(i).Position);
  }
  this->currentWorld->EnableAllModels();
  // common::Time::MSleep(5000);
  // this->currentWorld->EnablePhysicsEngine(true);
} // GaitRecorder::SetPose
// Register this plugin with the simulator
GZ_REGISTER_WORLD_PLUGIN(GaitRecorder)
} // namespace gazebo<|endoftext|>