<commit_before>#include "ProcessEvent.h"

#include <specialized/eventbackend.h>

#if defined(__linux__)
#include <linux/version.h>
#elif !defined(KERNEL_VERSION)
#define LINUX_VERSION_CODE 0
#define KERNEL_VERSION(a, b, c) 0
#endif

#if defined(__linux__) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) /* Linux 2.6.15+ */

// Linux
#include <linux/netlink.h>
#include <linux/connector.h>
#include <linux/cn_proc.h>

// PUT
#include <cxxutils/posix_helpers.h>
#include <cxxutils/socket_helpers.h>
#include <cxxutils/vterm.h>
#include <specialized/procstat.h>

enum {
  Read = 0,
  Write = 1,
};

struct message_t
{
  union {
    ProcessEvent::Flags action;
    uint32_t : 0;
  };
  pid_t pid;
};
static_assert(sizeof(message_t) == sizeof(uint64_t), "unexpected struct size");

// process flags
static constexpr uint8_t from_native_flags(const native_flags_t flags) noexcept
{
  return
      (flags & proc_event::PROC_EVENT_EXEC ? ProcessEvent::Exec : 0) |
      (flags & proc_event::PROC_EVENT_EXIT ? ProcessEvent::Exit : 0) |
      (flags & proc_event::PROC_EVENT_FORK ? ProcessEvent::Fork : 0) ;
}
/*
static constexpr native_flags_t to_native_flags(const uint8_t flags) noexcept
{
  return
      (flags & ProcessEvent::Exec ? native_flags_t(proc_event::PROC_EVENT_EXEC) : 0) | // Process called exec*()
      (flags & ProcessEvent::Exit ? native_flags_t(proc_event::PROC_EVENT_EXIT) : 0) | // Process exited
      (flags & ProcessEvent::Fork ? native_flags_t(proc_event::PROC_EVENT_FORK) : 0) ; // Process forked
}
*/

struct ProcessEvent::platform_dependant // process notification (process events connector)
{
  posix::fd_t fd;
  struct eventinfo_t
  {
    posix::fd_t fd[2]; // two fds for pipe based communication
    ProcessEvent::Flags_t flags;
  };

  std::unordered_map<pid_t, eventinfo_t> events;

  platform_dependant(void) noexcept
  {
    fd = posix::socket(EDomain::netlink, EType::datagram, EProtocol::connector);
    flaw(fd == posix::invalid_descriptor,
         terminal::warning,,,
         "Unable to open a netlink socket for Process Events Connector: %s", std::strerror(errno))

    sockaddr_nl sa_nl;
    sa_nl.nl_family = PF_NETLINK;
    sa_nl.nl_groups = CN_IDX_PROC;
    sa_nl.nl_pid = uint32_t(getpid());

    flaw(!posix::bind(fd, reinterpret_cast<struct sockaddr *>(&sa_nl), sizeof(sa_nl)),
         terminal::warning,,,
         "Process Events Connector requires root level access: %s", std::strerror(errno));

#pragma pack(push, 1)
    struct alignas(NLMSG_ALIGNTO) procconn_t // 32-bit alignment
    {
      nlmsghdr header; // 16 bytes
      cn_msg message;
      proc_cn_mcast_op operation;
    } procconn;
#pragma pack(pop)
    static_assert(sizeof(nlmsghdr) + sizeof(cn_msg) + sizeof(proc_cn_mcast_op) == sizeof(procconn_t), "compiler needs to pack struct");

    std::memset(&procconn, 0, sizeof(procconn));
    procconn.header.nlmsg_len = sizeof(procconn);
    procconn.header.nlmsg_pid = uint32_t(getpid());
    procconn.header.nlmsg_type = NLMSG_DONE;
    procconn.message.id.idx = CN_IDX_PROC;
    procconn.message.id.val = CN_VAL_PROC;
    procconn.message.len = sizeof(proc_cn_mcast_op);
    procconn.operation = PROC_CN_MCAST_LISTEN;

    flaw(posix::send(fd, &procconn, sizeof(procconn)) == posix::error_response,
         terminal::warning,,,
         "Failed to enable Process Events Connector notifications: %s", std::strerror(errno));

    EventBackend::add(fd, EventBackend::SimplePollReadFlags,
                      [this](posix::fd_t lambda_fd, native_flags_t) noexcept { read(lambda_fd); });

    std::fprintf(stderr, "%s%s\n", terminal::information, "Process Events Connector active");
  }

  ~platform_dependant(void) noexcept
  {
    EventBackend::remove(fd, EventBackend::SimplePollReadFlags);
    posix::close(fd);
    fd = posix::invalid_descriptor;
  }

  posix::fd_t add(pid_t pid, ProcessEvent::Flags_t flags) noexcept
  {
    eventinfo_t event;
    event.flags = flags;
    if(!posix::pipe(event.fd))
      return posix::invalid_descriptor;

    auto iter = events.emplace(pid, event);

    // add filter installation code here

    return event.fd[Read];
  }

  bool remove(pid_t pid) noexcept
  {
    auto iter = events.find(pid);
    if(iter == events.end())
      return false;

    // add filter removal code here

    posix::close(iter->second.fd[Read]);
    posix::close(iter->second.fd[Write]);
    events.erase(iter);
    return true;
  }

  void read(posix::fd_t procfd) noexcept
  {
#pragma pack(push, 1)
    struct alignas(NLMSG_ALIGNTO) procmsg_t // 32-bit alignment
    {
      nlmsghdr header; // 16 bytes
      cn_msg message;
      proc_event event;
    } procmsg;
#pragma pack(pop)
    static_assert(sizeof(nlmsghdr) + sizeof(cn_msg) + sizeof(proc_event) == sizeof(procmsg_t), "compiler needs to pack struct");

    pollfd fds = { procfd, POLLIN, 0 };
    while(posix::poll(&fds, 1, 0) > 0 && // while there are messages AND
          posix::recv(procfd, reinterpret_cast<void*>(&procmsg), sizeof(procmsg_t), 0) > 0) // read process event message
    {
      auto iter = events.find(procmsg.event.event_data.id.process_pid); // find event info for this PID
      if(iter != events.end()) // if found...
        posix::write(iter->second.fd[Write], &procmsg.event, sizeof(procmsg.event)); // write process event info into the communications pipe
    }
  }
} ProcessEvent::s_platform;

ProcessEvent::ProcessEvent(pid_t _pid, Flags_t _flags) noexcept
  : m_pid(_pid), m_flags(_flags), m_fd(posix::invalid_descriptor)
{
  m_fd = s_platform.add(m_pid, m_flags); // add PID to monitor and return communications pipe

  EventBackend::add(m_fd, EventBackend::SimplePollReadFlags, // connect communications pipe to a lambda function
                    [this](posix::fd_t lambda_fd, native_flags_t) noexcept
                    {
                      proc_event data;
                      pollfd fds = { lambda_fd, POLLIN, 0 };
                      while(posix::poll(&fds, 1, 0) > 0 && // while there is another event to be read
                            posix::read(lambda_fd, &data, sizeof(data)) > 0) // read the event
                        switch(from_native_flags(data.what)) // find the type of event
                        {
                          case Flags::Exec: // queue exec signal with PID
                            Object::enqueue(execed,
                                            data.event_data.exec.process_pid);
                            break;
                          case Flags::Exit: // queue exit signal with PID and exit code
                            if(data.event_data.exit.exit_signal) // if killed by a signal
                              Object::enqueue(killed,
                                              data.event_data.exit.process_pid,
                                              *reinterpret_cast<posix::signal::EId*>(&data.event_data.exit.exit_signal));
                            else // else exited by itself
                              Object::enqueue(exited,
                                              data.event_data.exit.process_pid,
                                              *reinterpret_cast<posix::error_t*>(&data.event_data.exit.exit_code));
                            break;
                          case Flags::Fork: // queue fork signal with PID and child PID
                            Object::enqueue(forked,
                                            data.event_data.fork.parent_pid,
                                            data.event_data.fork.child_pid);
                            break;
                        }
                    });
}

ProcessEvent::~ProcessEvent(void) noexcept
{
  EventBackend::remove(m_fd, EventBackend::SimplePollReadFlags);
  s_platform.remove(m_pid);
}
#elif defined(__linux__)
//&& LINUX_VERSION_CODE >= KERNEL_VERSION(X,X,X) /* Linux X.X.X+ */
# error No process event backend code exists in PDTK for Linux before version 2.6.15!  Please submit a patch!

#elif defined(__darwin__)    /* Darwin 7+     */ || \
      defined(__FreeBSD__)   /* FreeBSD 4.1+  */ || \
      defined(__DragonFly__) /* DragonFly BSD */ || \
      defined(__OpenBSD__)   /* OpenBSD 2.9+  */ || \
      defined(__NetBSD__)    /* NetBSD 2+     */

#include <sys/event.h> // kqueue

static constexpr native_flags_t composite_flag(uint16_t actions, int16_t filters, uint32_t flags) noexcept
  { return native_flags_t(actions) | (native_flags_t(uint16_t(filters)) << 16) | (native_flags_t(flags) << 32); }

static constexpr bool flag_subset(native_flags_t flags, native_flags_t subset)
  { return (flags & subset) == subset; }

static constexpr native_flags_t to_native_flags(const uint8_t flags) noexcept
{
  return
      (flags & ProcessEvent::Exec ? composite_flag(0, EVFILT_PROC, NOTE_EXEC) : 0) |
      (flags & ProcessEvent::Exit ? composite_flag(0, EVFILT_PROC, NOTE_EXIT) : 0) |
      (flags & ProcessEvent::Fork ? composite_flag(0, EVFILT_PROC, NOTE_FORK) : 0) ;
}

static constexpr ushort extract_filter(native_flags_t flags) noexcept
  { return (flags >> 16) & 0xFFFF; }

template<typename rtype>
static constexpr rtype extract_flags(native_flags_t flags) noexcept
  { return flags >> 32; }

ProcessEvent::ProcessEvent(pid_t _pid, Flags_t _flags) noexcept
  : m_pid(_pid), m_flags(_flags), m_fd(posix::invalid_descriptor)
{
  EventBackend::add(m_pid, to_native_flags(m_flags), // connect PID event to lambda function
                    [this](posix::fd_t lambda_fd, native_flags_t lambda_flags) noexcept
                    {
                      switch(extract_filter(lambda_fd)) // switch by filtered event type
                      {
                        case Flags::Exec: // queue exec signal with PID
                          Object::enqueue_copy(execed, m_pid);
                          break;
                        case Flags::Exit: // queue exit signal with PID and exit code
                          Object::enqueue_copy(exited, m_pid, extract_flags<posix::error_t>(lambda_fd));
                          break;
                        case Flags::Fork: // queue fork signal with PID and child PID
                          Object::enqueue_copy(forked, m_pid, extract_flags<pid_t>(lambda_fd));
                          break;
                      }
                    });
}

ProcessEvent::~ProcessEvent(void) noexcept
{
  EventBackend::remove(m_pid, to_native_flags(m_flags)); // disconnect PID with flags
}

#elif defined(__solaris__) // Solaris / OpenSolaris / OpenIndiana / illumos
# error No process event backend code exists in PDTK for Solaris / OpenSolaris / OpenIndiana / illumos!  Please submit a patch!

#elif defined(__minix) // MINIX
# error No process event backend code exists in PDTK for MINIX!  Please submit a patch!

#elif defined(__QNX__) // QNX
// QNX docs: http://www.qnx.com/developers/docs/7.0.0/index.html#com.qnx.doc.neutrino.devctl/topic/about.html
# error No process event backend code exists in PDTK for QNX!  Please submit a patch!

#elif defined(__hpux) // HP-UX
# error No process event backend code exists in PDTK for HP-UX!  Please submit a patch!

#elif defined(_AIX) // IBM AIX
# error No process event backend code exists in PDTK for IBM AIX!  Please submit a patch!

#elif defined(BSD)
# error Unrecognized BSD derivative!

#elif defined(__unix__)
# error Unrecognized UNIX variant!

#else
# error This platform is not supported.
#endif
<commit_msg>use lambda_flags and change PDTK to PUT<commit_after>#include "ProcessEvent.h"

#include <specialized/eventbackend.h>

#if defined(__linux__)
#include <linux/version.h>
#elif !defined(KERNEL_VERSION)
#define LINUX_VERSION_CODE 0
#define KERNEL_VERSION(a, b, c) 0
#endif

#if defined(__linux__) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) /* Linux 2.6.15+ */

// Linux
#include <linux/netlink.h>
#include <linux/connector.h>
#include <linux/cn_proc.h>

// PUT
#include <cxxutils/posix_helpers.h>
#include <cxxutils/socket_helpers.h>
#include <cxxutils/vterm.h>
#include <specialized/procstat.h>

enum {
  Read = 0,
  Write = 1,
};

struct message_t
{
  union {
    ProcessEvent::Flags action;
    uint32_t : 0;
  };
  pid_t pid;
};
static_assert(sizeof(message_t) == sizeof(uint64_t), "unexpected struct size");

// process flags
static constexpr uint8_t from_native_flags(const native_flags_t flags) noexcept
{
  return
      (flags & proc_event::PROC_EVENT_EXEC ? ProcessEvent::Exec : 0) |
      (flags & proc_event::PROC_EVENT_EXIT ? ProcessEvent::Exit : 0) |
      (flags & proc_event::PROC_EVENT_FORK ? ProcessEvent::Fork : 0) ;
}
/*
static constexpr native_flags_t to_native_flags(const uint8_t flags) noexcept
{
  return
      (flags & ProcessEvent::Exec ? native_flags_t(proc_event::PROC_EVENT_EXEC) : 0) | // Process called exec*()
      (flags & ProcessEvent::Exit ? native_flags_t(proc_event::PROC_EVENT_EXIT) : 0) | // Process exited
      (flags & ProcessEvent::Fork ? native_flags_t(proc_event::PROC_EVENT_FORK) : 0) ; // Process forked
}
*/

struct ProcessEvent::platform_dependant // process notification (process events connector)
{
  posix::fd_t fd;
  struct eventinfo_t
  {
    posix::fd_t fd[2]; // two fds for pipe based communication
    ProcessEvent::Flags_t flags;
  };

  std::unordered_map<pid_t, eventinfo_t> events;

  platform_dependant(void) noexcept
  {
    fd = posix::socket(EDomain::netlink, EType::datagram, EProtocol::connector);
    flaw(fd == posix::invalid_descriptor,
         terminal::warning,,,
         "Unable to open a netlink socket for Process Events Connector: %s", std::strerror(errno))

    sockaddr_nl sa_nl;
    sa_nl.nl_family = PF_NETLINK;
    sa_nl.nl_groups = CN_IDX_PROC;
    sa_nl.nl_pid = uint32_t(getpid());

    flaw(!posix::bind(fd, reinterpret_cast<struct sockaddr *>(&sa_nl), sizeof(sa_nl)),
         terminal::warning,,,
         "Process Events Connector requires root level access: %s", std::strerror(errno));

#pragma pack(push, 1)
    struct alignas(NLMSG_ALIGNTO) procconn_t // 32-bit alignment
    {
      nlmsghdr header; // 16 bytes
      cn_msg message;
      proc_cn_mcast_op operation;
    } procconn;
#pragma pack(pop)
    static_assert(sizeof(nlmsghdr) + sizeof(cn_msg) + sizeof(proc_cn_mcast_op) == sizeof(procconn_t), "compiler needs to pack struct");

    std::memset(&procconn, 0, sizeof(procconn));
    procconn.header.nlmsg_len = sizeof(procconn);
    procconn.header.nlmsg_pid = uint32_t(getpid());
    procconn.header.nlmsg_type = NLMSG_DONE;
    procconn.message.id.idx = CN_IDX_PROC;
    procconn.message.id.val = CN_VAL_PROC;
    procconn.message.len = sizeof(proc_cn_mcast_op);
    procconn.operation = PROC_CN_MCAST_LISTEN;

    flaw(posix::send(fd, &procconn, sizeof(procconn)) == posix::error_response,
         terminal::warning,,,
         "Failed to enable Process Events Connector notifications: %s", std::strerror(errno));

    EventBackend::add(fd, EventBackend::SimplePollReadFlags,
                      [this](posix::fd_t lambda_fd, native_flags_t) noexcept { read(lambda_fd); });

    std::fprintf(stderr, "%s%s\n", terminal::information, "Process Events Connector active");
  }

  ~platform_dependant(void) noexcept
  {
    EventBackend::remove(fd, EventBackend::SimplePollReadFlags);
    posix::close(fd);
    fd = posix::invalid_descriptor;
  }

  posix::fd_t add(pid_t pid, ProcessEvent::Flags_t flags) noexcept
  {
    eventinfo_t event;
    event.flags = flags;
    if(!posix::pipe(event.fd))
      return posix::invalid_descriptor;

    auto iter = events.emplace(pid, event);

    // add filter installation code here

    return event.fd[Read];
  }

  bool remove(pid_t pid) noexcept
  {
    auto iter = events.find(pid);
    if(iter == events.end())
      return false;

    // add filter removal code here

    posix::close(iter->second.fd[Read]);
    posix::close(iter->second.fd[Write]);
    events.erase(iter);
    return true;
  }

  void read(posix::fd_t procfd) noexcept
  {
#pragma pack(push, 1)
    struct alignas(NLMSG_ALIGNTO) procmsg_t // 32-bit alignment
    {
      nlmsghdr header; // 16 bytes
      cn_msg message;
      proc_event event;
    } procmsg;
#pragma pack(pop)
    static_assert(sizeof(nlmsghdr) + sizeof(cn_msg) + sizeof(proc_event) == sizeof(procmsg_t), "compiler needs to pack struct");

    pollfd fds = { procfd, POLLIN, 0 };
    while(posix::poll(&fds, 1, 0) > 0 && // while there are messages AND
          posix::recv(procfd, reinterpret_cast<void*>(&procmsg), sizeof(procmsg_t), 0) > 0) // read process event message
    {
      auto iter = events.find(procmsg.event.event_data.id.process_pid); // find event info for this PID
      if(iter != events.end()) // if found...
        posix::write(iter->second.fd[Write], &procmsg.event, sizeof(procmsg.event)); // write process event info into the communications pipe
    }
  }
} ProcessEvent::s_platform;

ProcessEvent::ProcessEvent(pid_t _pid, Flags_t _flags) noexcept
  : m_pid(_pid), m_flags(_flags), m_fd(posix::invalid_descriptor)
{
  m_fd = s_platform.add(m_pid, m_flags); // add PID to monitor and return communications pipe

  EventBackend::add(m_fd, EventBackend::SimplePollReadFlags, // connect communications pipe to a lambda function
                    [this](posix::fd_t lambda_fd, native_flags_t) noexcept
                    {
                      proc_event data;
                      pollfd fds = { lambda_fd, POLLIN, 0 };
                      while(posix::poll(&fds, 1, 0) > 0 && // while there is another event to be read
                            posix::read(lambda_fd, &data, sizeof(data)) > 0) // read the event
                        switch(from_native_flags(data.what)) // find the type of event
                        {
                          case Flags::Exec: // queue exec signal with PID
                            Object::enqueue(execed,
                                            data.event_data.exec.process_pid);
                            break;
                          case Flags::Exit: // queue exit signal with PID and exit code
                            if(data.event_data.exit.exit_signal) // if killed by a signal
                              Object::enqueue(killed,
                                              data.event_data.exit.process_pid,
                                              *reinterpret_cast<posix::signal::EId*>(&data.event_data.exit.exit_signal));
                            else // else exited by itself
                              Object::enqueue(exited,
                                              data.event_data.exit.process_pid,
                                              *reinterpret_cast<posix::error_t*>(&data.event_data.exit.exit_code));
                            break;
                          case Flags::Fork: // queue fork signal with PID and child PID
                            Object::enqueue(forked,
                                            data.event_data.fork.parent_pid,
                                            data.event_data.fork.child_pid);
                            break;
                        }
                    });
}

ProcessEvent::~ProcessEvent(void) noexcept
{
  EventBackend::remove(m_fd, EventBackend::SimplePollReadFlags);
  s_platform.remove(m_pid);
}
#elif defined(__linux__)
//&& LINUX_VERSION_CODE >= KERNEL_VERSION(X,X,X) /* Linux X.X.X+ */
# error No process event backend code exists in PUT for Linux before version 2.6.15!  Please submit a patch!

#elif defined(__darwin__)    /* Darwin 7+     */ || \
      defined(__FreeBSD__)   /* FreeBSD 4.1+  */ || \
      defined(__DragonFly__) /* DragonFly BSD */ || \
      defined(__OpenBSD__)   /* OpenBSD 2.9+  */ || \
      defined(__NetBSD__)    /* NetBSD 2+     */

#include <sys/event.h> // kqueue

static constexpr native_flags_t composite_flag(uint16_t actions, int16_t filters, uint32_t flags) noexcept
  { return native_flags_t(actions) | (native_flags_t(uint16_t(filters)) << 16) | (native_flags_t(flags) << 32); }

static constexpr bool flag_subset(native_flags_t flags, native_flags_t subset)
  { return (flags & subset) == subset; }

static constexpr native_flags_t to_native_flags(const uint8_t flags) noexcept
{
  return
      (flags & ProcessEvent::Exec ? composite_flag(0, EVFILT_PROC, NOTE_EXEC) : 0) |
      (flags & ProcessEvent::Exit ? composite_flag(0, EVFILT_PROC, NOTE_EXIT) : 0) |
      (flags & ProcessEvent::Fork ? composite_flag(0, EVFILT_PROC, NOTE_FORK) : 0) ;
}

static constexpr ushort extract_filter(native_flags_t flags) noexcept
  { return (flags >> 16) & 0xFFFF; }

template<typename rtype>
static constexpr rtype extract_flags(native_flags_t flags) noexcept
  { return flags >> 32; }

ProcessEvent::ProcessEvent(pid_t _pid, Flags_t _flags) noexcept
  : m_pid(_pid), m_flags(_flags), m_fd(posix::invalid_descriptor)
{
  EventBackend::add(m_pid, to_native_flags(m_flags), // connect PID event to lambda function
                    [this](posix::fd_t lambda_fd, native_flags_t lambda_flags) noexcept
                    {
                      switch(extract_filter(lambda_flags)) // switch by filtered event type
                      {
                        case Flags::Exec: // queue exec signal with PID
                          Object::enqueue_copy(execed, m_pid);
                          break;
                        case Flags::Exit: // queue exit signal with PID and exit code
                          Object::enqueue_copy(exited, m_pid, extract_flags<posix::error_t>(lambda_flags));
                          break;
                        case Flags::Fork: // queue fork signal with PID and child PID
                          Object::enqueue_copy(forked, m_pid, extract_flags<pid_t>(lambda_flags));
                          break;
                      }
                    });
}

ProcessEvent::~ProcessEvent(void) noexcept
{
  EventBackend::remove(m_pid, to_native_flags(m_flags)); // disconnect PID with flags
}

#elif defined(__solaris__) // Solaris / OpenSolaris / OpenIndiana / illumos
# error No process event backend code exists in PUT for Solaris / OpenSolaris / OpenIndiana / illumos!  Please submit a patch!

#elif defined(__minix) // MINIX
# error No process event backend code exists in PUT for MINIX!  Please submit a patch!

#elif defined(__QNX__) // QNX
// QNX docs: http://www.qnx.com/developers/docs/7.0.0/index.html#com.qnx.doc.neutrino.devctl/topic/about.html
# error No process event backend code exists in PUT for QNX!  Please submit a patch!

#elif defined(__hpux) // HP-UX
# error No process event backend code exists in PUT for HP-UX!  Please submit a patch!

#elif defined(_AIX) // IBM AIX
# error No process event backend code exists in PUT for IBM AIX!  Please submit a patch!

#elif defined(BSD)
# error Unrecognized BSD derivative!

#elif defined(__unix__)
# error Unrecognized UNIX variant!

#else
# error This platform is not supported.
#endif
<|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/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/net/prediction_options.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/translate/core/common/translate_pref_names.h"
#include "content/public/browser/notification_service.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/test_extension_registry_observer.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"

namespace {

void ReleaseBrowserProcessModule() {
  g_browser_process->ReleaseModule();
}

}  // namespace

class ExtensionPreferenceApiTest : public ExtensionApiTest {
 protected:
  ExtensionPreferenceApiTest() : profile_(NULL) {}

  void CheckPreferencesSet() {
    PrefService* prefs = profile_->GetPrefs();
    const PrefService::Preference* pref = prefs->FindPreference(
        prefs::kBlockThirdPartyCookies);
    ASSERT_TRUE(pref);
    EXPECT_TRUE(pref->IsExtensionControlled());
    EXPECT_TRUE(prefs->GetBoolean(prefs::kAlternateErrorPagesEnabled));
    EXPECT_TRUE(prefs->GetBoolean(autofill::prefs::kAutofillEnabled));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kEnableHyperlinkAuditing));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kEnableReferrers));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kEnableTranslate));
    EXPECT_EQ(chrome_browser_net::NETWORK_PREDICTION_DEFAULT,
              prefs->GetInteger(prefs::kNetworkPredictionOptions));
    EXPECT_TRUE(prefs->GetBoolean(
        password_manager::prefs::kPasswordManagerSavingEnabled));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kSafeBrowsingEnabled));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kSearchSuggestEnabled));
  }

  void CheckPreferencesCleared() {
    PrefService* prefs = profile_->GetPrefs();
    const PrefService::Preference* pref = prefs->FindPreference(
        prefs::kBlockThirdPartyCookies);
    ASSERT_TRUE(pref);
    EXPECT_FALSE(pref->IsExtensionControlled());
    EXPECT_FALSE(prefs->GetBoolean(prefs::kAlternateErrorPagesEnabled));
    EXPECT_FALSE(prefs->GetBoolean(autofill::prefs::kAutofillEnabled));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kEnableHyperlinkAuditing));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kEnableReferrers));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kEnableTranslate));
    EXPECT_EQ(chrome_browser_net::NETWORK_PREDICTION_NEVER,
              prefs->GetInteger(prefs::kNetworkPredictionOptions));
    EXPECT_FALSE(prefs->GetBoolean(
        password_manager::prefs::kPasswordManagerSavingEnabled));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kSafeBrowsingEnabled));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kSearchSuggestEnabled));
  }

  void SetUpOnMainThread() override {
    ExtensionApiTest::SetUpOnMainThread();

    // The browser might get closed later (and therefore be destroyed), so we
    // save the profile.
    profile_ = browser()->profile();

    // Closing the last browser window also releases a module reference. Make
    // sure it's not the last one, so the message loop doesn't quit
    // unexpectedly.
    g_browser_process->AddRefModule();
  }

  void TearDownOnMainThread() override {
    // ReleaseBrowserProcessModule() needs to be called in a message loop, so we
    // post a task to do it, then run the message loop.
    base::MessageLoop::current()->PostTask(
        FROM_HERE, base::Bind(&ReleaseBrowserProcessModule));
    content::RunAllPendingInMessageLoop();

    ExtensionApiTest::TearDownOnMainThread();
  }

  Profile* profile_;
};

// http://crbug.com/177163
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_Standard DISABLED_Standard
#else
#define MAYBE_Standard Standard
#endif
IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, MAYBE_Standard) {
  PrefService* prefs = profile_->GetPrefs();
  prefs->SetBoolean(prefs::kAlternateErrorPagesEnabled, false);
  prefs->SetBoolean(autofill::prefs::kAutofillEnabled, false);
  prefs->SetBoolean(prefs::kBlockThirdPartyCookies, true);
  prefs->SetBoolean(prefs::kEnableHyperlinkAuditing, false);
  prefs->SetBoolean(prefs::kEnableReferrers, false);
  prefs->SetBoolean(prefs::kEnableTranslate, false);
  prefs->SetInteger(prefs::kNetworkPredictionOptions,
                    chrome_browser_net::NETWORK_PREDICTION_NEVER);
  prefs->SetBoolean(password_manager::prefs::kPasswordManagerSavingEnabled,
                    false);
  prefs->SetBoolean(prefs::kSafeBrowsingEnabled, false);
  prefs->SetBoolean(prefs::kSearchSuggestEnabled, false);
#if defined(ENABLE_WEBRTC)
  prefs->SetBoolean(prefs::kWebRTCMultipleRoutesEnabled, false);
#endif

  const char kExtensionPath[] = "preference/standard";

  EXPECT_TRUE(RunExtensionSubtest(kExtensionPath, "test.html")) << message_;
  CheckPreferencesSet();

  // The settings should not be reset when the extension is reloaded.
  ReloadExtension(last_loaded_extension_id());
  CheckPreferencesSet();

  // Uninstalling and installing the extension (without running the test that
  // calls the extension API) should clear the settings.
  extensions::TestExtensionRegistryObserver observer(
      extensions::ExtensionRegistry::Get(profile_), last_loaded_extension_id());
  UninstallExtension(last_loaded_extension_id());
  observer.WaitForExtensionUninstalled();
  CheckPreferencesCleared();

  LoadExtension(test_data_dir_.AppendASCII(kExtensionPath));
  CheckPreferencesCleared();
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, PersistentIncognito) {
  PrefService* prefs = profile_->GetPrefs();
  prefs->SetBoolean(prefs::kBlockThirdPartyCookies, false);

  EXPECT_TRUE(
      RunExtensionTestIncognito("preference/persistent_incognito")) <<
      message_;

  // Setting an incognito preference should not create an incognito profile.
  EXPECT_FALSE(profile_->HasOffTheRecordProfile());

  PrefService* otr_prefs = profile_->GetOffTheRecordProfile()->GetPrefs();
  const PrefService::Preference* pref =
      otr_prefs->FindPreference(prefs::kBlockThirdPartyCookies);
  ASSERT_TRUE(pref);
  EXPECT_TRUE(pref->IsExtensionControlled());
  EXPECT_TRUE(otr_prefs->GetBoolean(prefs::kBlockThirdPartyCookies));

  pref = prefs->FindPreference(prefs::kBlockThirdPartyCookies);
  ASSERT_TRUE(pref);
  EXPECT_FALSE(pref->IsExtensionControlled());
  EXPECT_FALSE(prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
}

// Flakily times out: http://crbug.com/106144
IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, DISABLED_IncognitoDisabled) {
  EXPECT_FALSE(RunExtensionTest("preference/persistent_incognito"));
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, SessionOnlyIncognito) {
  PrefService* prefs = profile_->GetPrefs();
  prefs->SetBoolean(prefs::kBlockThirdPartyCookies, false);

  EXPECT_TRUE(
      RunExtensionTestIncognito("preference/session_only_incognito")) <<
      message_;

  EXPECT_TRUE(profile_->HasOffTheRecordProfile());

  PrefService* otr_prefs = profile_->GetOffTheRecordProfile()->GetPrefs();
  const PrefService::Preference* pref =
      otr_prefs->FindPreference(prefs::kBlockThirdPartyCookies);
  ASSERT_TRUE(pref);
  EXPECT_TRUE(pref->IsExtensionControlled());
  EXPECT_FALSE(otr_prefs->GetBoolean(prefs::kBlockThirdPartyCookies));

  pref = prefs->FindPreference(prefs::kBlockThirdPartyCookies);
  ASSERT_TRUE(pref);
  EXPECT_FALSE(pref->IsExtensionControlled());
  EXPECT_FALSE(prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, Clear) {
  PrefService* prefs = profile_->GetPrefs();
  prefs->SetBoolean(prefs::kBlockThirdPartyCookies, true);

  EXPECT_TRUE(RunExtensionTest("preference/clear")) << message_;

  const PrefService::Preference* pref = prefs->FindPreference(
      prefs::kBlockThirdPartyCookies);
  ASSERT_TRUE(pref);
  EXPECT_FALSE(pref->IsExtensionControlled());
  EXPECT_EQ(true, prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, OnChange) {
  EXPECT_TRUE(RunExtensionTestIncognito("preference/onchange")) <<
      message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, OnChangeSplit) {
  extensions::ResultCatcher catcher;
  catcher.RestrictToBrowserContext(profile_);
  extensions::ResultCatcher catcher_incognito;
  catcher_incognito.RestrictToBrowserContext(
      profile_->GetOffTheRecordProfile());

  // Open an incognito window.
  ui_test_utils::OpenURLOffTheRecord(profile_, GURL("chrome://newtab/"));

  // changeDefault listeners.
  ExtensionTestMessageListener listener1("changeDefault regular ready", true);
  ExtensionTestMessageListener listener_incognito1(
      "changeDefault incognito ready", true);

  // changeIncognitoOnly listeners.
  ExtensionTestMessageListener listener2(
      "changeIncognitoOnly regular ready", true);
  ExtensionTestMessageListener listener_incognito2(
      "changeIncognitoOnly incognito ready", true);
  ExtensionTestMessageListener listener3(
      "changeIncognitoOnly regular listening", true);
  ExtensionTestMessageListener listener_incognito3(
      "changeIncognitoOnly incognito pref set", false);

  // changeDefaultOnly listeners.
  ExtensionTestMessageListener listener4(
      "changeDefaultOnly regular ready", true);
  ExtensionTestMessageListener listener_incognito4(
      "changeDefaultOnly incognito ready", true);
  ExtensionTestMessageListener listener5(
      "changeDefaultOnly regular pref set", false);
  ExtensionTestMessageListener listener_incognito5(
      "changeDefaultOnly incognito listening", true);

  // changeIncognitoOnlyBack listeners.
  ExtensionTestMessageListener listener6(
      "changeIncognitoOnlyBack regular ready", true);
  ExtensionTestMessageListener listener_incognito6(
      "changeIncognitoOnlyBack incognito ready", true);
  ExtensionTestMessageListener listener7(
      "changeIncognitoOnlyBack regular listening", true);
  ExtensionTestMessageListener listener_incognito7(
      "changeIncognitoOnlyBack incognito pref set", false);

  // clearIncognito listeners.
  ExtensionTestMessageListener listener8(
      "clearIncognito regular ready", true);
  ExtensionTestMessageListener listener_incognito8(
      "clearIncognito incognito ready", true);
  ExtensionTestMessageListener listener9(
      "clearIncognito regular listening", true);
  ExtensionTestMessageListener listener_incognito9(
      "clearIncognito incognito pref cleared", false);

  // clearDefault listeners.
  ExtensionTestMessageListener listener10(
      "clearDefault regular ready", true);
  ExtensionTestMessageListener listener_incognito10(
      "clearDefault incognito ready", true);

  base::FilePath extension_data_dir =
      test_data_dir_.AppendASCII("preference").AppendASCII("onchange_split");
  ASSERT_TRUE(LoadExtensionIncognito(extension_data_dir));

  // Test 1 - changeDefault
  EXPECT_TRUE(listener1.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito1.WaitUntilSatisfied()); // Incognito ready
  listener1.Reply("ok");
  listener_incognito1.Reply("ok");

  // Test 2 - changeIncognitoOnly
  EXPECT_TRUE(listener2.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito2.WaitUntilSatisfied()); // Incognito ready
  EXPECT_TRUE(listener3.WaitUntilSatisfied()); // Regular listening
  listener2.Reply("ok");
  listener_incognito2.Reply("ok");
  // Incognito preference set -- notify the regular listener
  EXPECT_TRUE(listener_incognito3.WaitUntilSatisfied());
  listener3.Reply("ok");

  // Test 3 - changeDefaultOnly
  EXPECT_TRUE(listener4.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito4.WaitUntilSatisfied()); // Incognito ready
  EXPECT_TRUE(listener_incognito5.WaitUntilSatisfied()); // Incognito listening
  listener4.Reply("ok");
  listener_incognito4.Reply("ok");
  // Regular preference set - notify the incognito listener
  EXPECT_TRUE(listener5.WaitUntilSatisfied());
  listener_incognito5.Reply("ok");

  // Test 4 - changeIncognitoOnlyBack
  EXPECT_TRUE(listener6.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito6.WaitUntilSatisfied()); // Incognito ready
  EXPECT_TRUE(listener7.WaitUntilSatisfied()); // Regular listening
  listener6.Reply("ok");
  listener_incognito6.Reply("ok");
  // Incognito preference set -- notify the regular listener
  EXPECT_TRUE(listener_incognito7.WaitUntilSatisfied());
  listener7.Reply("ok");

  // Test 5 - clearIncognito
  EXPECT_TRUE(listener8.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito8.WaitUntilSatisfied()); // Incognito ready
  EXPECT_TRUE(listener9.WaitUntilSatisfied()); // Regular listening
  listener8.Reply("ok");
  listener_incognito8.Reply("ok");
  // Incognito preference cleared -- notify the regular listener
  EXPECT_TRUE(listener_incognito9.WaitUntilSatisfied());
  listener9.Reply("ok");

  // Test 6 - clearDefault
  EXPECT_TRUE(listener10.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito10.WaitUntilSatisfied()); // Incognito ready
  listener10.Reply("ok");
  listener_incognito10.Reply("ok");

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message();
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, DataReductionProxy) {
  EXPECT_TRUE(RunExtensionTest("preference/data_reduction_proxy")) <<
      message_;
}
<commit_msg>Disable flaky ExtensionPreferenceApiTest.DataReductionProxy on Windows.<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/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/net/prediction_options.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/translate/core/common/translate_pref_names.h"
#include "content/public/browser/notification_service.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/test_extension_registry_observer.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"

namespace {

void ReleaseBrowserProcessModule() {
  g_browser_process->ReleaseModule();
}

}  // namespace

class ExtensionPreferenceApiTest : public ExtensionApiTest {
 protected:
  ExtensionPreferenceApiTest() : profile_(NULL) {}

  void CheckPreferencesSet() {
    PrefService* prefs = profile_->GetPrefs();
    const PrefService::Preference* pref = prefs->FindPreference(
        prefs::kBlockThirdPartyCookies);
    ASSERT_TRUE(pref);
    EXPECT_TRUE(pref->IsExtensionControlled());
    EXPECT_TRUE(prefs->GetBoolean(prefs::kAlternateErrorPagesEnabled));
    EXPECT_TRUE(prefs->GetBoolean(autofill::prefs::kAutofillEnabled));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kEnableHyperlinkAuditing));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kEnableReferrers));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kEnableTranslate));
    EXPECT_EQ(chrome_browser_net::NETWORK_PREDICTION_DEFAULT,
              prefs->GetInteger(prefs::kNetworkPredictionOptions));
    EXPECT_TRUE(prefs->GetBoolean(
        password_manager::prefs::kPasswordManagerSavingEnabled));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kSafeBrowsingEnabled));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kSearchSuggestEnabled));
  }

  void CheckPreferencesCleared() {
    PrefService* prefs = profile_->GetPrefs();
    const PrefService::Preference* pref = prefs->FindPreference(
        prefs::kBlockThirdPartyCookies);
    ASSERT_TRUE(pref);
    EXPECT_FALSE(pref->IsExtensionControlled());
    EXPECT_FALSE(prefs->GetBoolean(prefs::kAlternateErrorPagesEnabled));
    EXPECT_FALSE(prefs->GetBoolean(autofill::prefs::kAutofillEnabled));
    EXPECT_TRUE(prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kEnableHyperlinkAuditing));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kEnableReferrers));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kEnableTranslate));
    EXPECT_EQ(chrome_browser_net::NETWORK_PREDICTION_NEVER,
              prefs->GetInteger(prefs::kNetworkPredictionOptions));
    EXPECT_FALSE(prefs->GetBoolean(
        password_manager::prefs::kPasswordManagerSavingEnabled));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kSafeBrowsingEnabled));
    EXPECT_FALSE(prefs->GetBoolean(prefs::kSearchSuggestEnabled));
  }

  void SetUpOnMainThread() override {
    ExtensionApiTest::SetUpOnMainThread();

    // The browser might get closed later (and therefore be destroyed), so we
    // save the profile.
    profile_ = browser()->profile();

    // Closing the last browser window also releases a module reference. Make
    // sure it's not the last one, so the message loop doesn't quit
    // unexpectedly.
    g_browser_process->AddRefModule();
  }

  void TearDownOnMainThread() override {
    // ReleaseBrowserProcessModule() needs to be called in a message loop, so we
    // post a task to do it, then run the message loop.
    base::MessageLoop::current()->PostTask(
        FROM_HERE, base::Bind(&ReleaseBrowserProcessModule));
    content::RunAllPendingInMessageLoop();

    ExtensionApiTest::TearDownOnMainThread();
  }

  Profile* profile_;
};

// http://crbug.com/177163
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_Standard DISABLED_Standard
#else
#define MAYBE_Standard Standard
#endif
IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, MAYBE_Standard) {
  PrefService* prefs = profile_->GetPrefs();
  prefs->SetBoolean(prefs::kAlternateErrorPagesEnabled, false);
  prefs->SetBoolean(autofill::prefs::kAutofillEnabled, false);
  prefs->SetBoolean(prefs::kBlockThirdPartyCookies, true);
  prefs->SetBoolean(prefs::kEnableHyperlinkAuditing, false);
  prefs->SetBoolean(prefs::kEnableReferrers, false);
  prefs->SetBoolean(prefs::kEnableTranslate, false);
  prefs->SetInteger(prefs::kNetworkPredictionOptions,
                    chrome_browser_net::NETWORK_PREDICTION_NEVER);
  prefs->SetBoolean(password_manager::prefs::kPasswordManagerSavingEnabled,
                    false);
  prefs->SetBoolean(prefs::kSafeBrowsingEnabled, false);
  prefs->SetBoolean(prefs::kSearchSuggestEnabled, false);
#if defined(ENABLE_WEBRTC)
  prefs->SetBoolean(prefs::kWebRTCMultipleRoutesEnabled, false);
#endif

  const char kExtensionPath[] = "preference/standard";

  EXPECT_TRUE(RunExtensionSubtest(kExtensionPath, "test.html")) << message_;
  CheckPreferencesSet();

  // The settings should not be reset when the extension is reloaded.
  ReloadExtension(last_loaded_extension_id());
  CheckPreferencesSet();

  // Uninstalling and installing the extension (without running the test that
  // calls the extension API) should clear the settings.
  extensions::TestExtensionRegistryObserver observer(
      extensions::ExtensionRegistry::Get(profile_), last_loaded_extension_id());
  UninstallExtension(last_loaded_extension_id());
  observer.WaitForExtensionUninstalled();
  CheckPreferencesCleared();

  LoadExtension(test_data_dir_.AppendASCII(kExtensionPath));
  CheckPreferencesCleared();
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, PersistentIncognito) {
  PrefService* prefs = profile_->GetPrefs();
  prefs->SetBoolean(prefs::kBlockThirdPartyCookies, false);

  EXPECT_TRUE(
      RunExtensionTestIncognito("preference/persistent_incognito")) <<
      message_;

  // Setting an incognito preference should not create an incognito profile.
  EXPECT_FALSE(profile_->HasOffTheRecordProfile());

  PrefService* otr_prefs = profile_->GetOffTheRecordProfile()->GetPrefs();
  const PrefService::Preference* pref =
      otr_prefs->FindPreference(prefs::kBlockThirdPartyCookies);
  ASSERT_TRUE(pref);
  EXPECT_TRUE(pref->IsExtensionControlled());
  EXPECT_TRUE(otr_prefs->GetBoolean(prefs::kBlockThirdPartyCookies));

  pref = prefs->FindPreference(prefs::kBlockThirdPartyCookies);
  ASSERT_TRUE(pref);
  EXPECT_FALSE(pref->IsExtensionControlled());
  EXPECT_FALSE(prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
}

// Flakily times out: http://crbug.com/106144
IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, DISABLED_IncognitoDisabled) {
  EXPECT_FALSE(RunExtensionTest("preference/persistent_incognito"));
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, SessionOnlyIncognito) {
  PrefService* prefs = profile_->GetPrefs();
  prefs->SetBoolean(prefs::kBlockThirdPartyCookies, false);

  EXPECT_TRUE(
      RunExtensionTestIncognito("preference/session_only_incognito")) <<
      message_;

  EXPECT_TRUE(profile_->HasOffTheRecordProfile());

  PrefService* otr_prefs = profile_->GetOffTheRecordProfile()->GetPrefs();
  const PrefService::Preference* pref =
      otr_prefs->FindPreference(prefs::kBlockThirdPartyCookies);
  ASSERT_TRUE(pref);
  EXPECT_TRUE(pref->IsExtensionControlled());
  EXPECT_FALSE(otr_prefs->GetBoolean(prefs::kBlockThirdPartyCookies));

  pref = prefs->FindPreference(prefs::kBlockThirdPartyCookies);
  ASSERT_TRUE(pref);
  EXPECT_FALSE(pref->IsExtensionControlled());
  EXPECT_FALSE(prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, Clear) {
  PrefService* prefs = profile_->GetPrefs();
  prefs->SetBoolean(prefs::kBlockThirdPartyCookies, true);

  EXPECT_TRUE(RunExtensionTest("preference/clear")) << message_;

  const PrefService::Preference* pref = prefs->FindPreference(
      prefs::kBlockThirdPartyCookies);
  ASSERT_TRUE(pref);
  EXPECT_FALSE(pref->IsExtensionControlled());
  EXPECT_EQ(true, prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, OnChange) {
  EXPECT_TRUE(RunExtensionTestIncognito("preference/onchange")) <<
      message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, OnChangeSplit) {
  extensions::ResultCatcher catcher;
  catcher.RestrictToBrowserContext(profile_);
  extensions::ResultCatcher catcher_incognito;
  catcher_incognito.RestrictToBrowserContext(
      profile_->GetOffTheRecordProfile());

  // Open an incognito window.
  ui_test_utils::OpenURLOffTheRecord(profile_, GURL("chrome://newtab/"));

  // changeDefault listeners.
  ExtensionTestMessageListener listener1("changeDefault regular ready", true);
  ExtensionTestMessageListener listener_incognito1(
      "changeDefault incognito ready", true);

  // changeIncognitoOnly listeners.
  ExtensionTestMessageListener listener2(
      "changeIncognitoOnly regular ready", true);
  ExtensionTestMessageListener listener_incognito2(
      "changeIncognitoOnly incognito ready", true);
  ExtensionTestMessageListener listener3(
      "changeIncognitoOnly regular listening", true);
  ExtensionTestMessageListener listener_incognito3(
      "changeIncognitoOnly incognito pref set", false);

  // changeDefaultOnly listeners.
  ExtensionTestMessageListener listener4(
      "changeDefaultOnly regular ready", true);
  ExtensionTestMessageListener listener_incognito4(
      "changeDefaultOnly incognito ready", true);
  ExtensionTestMessageListener listener5(
      "changeDefaultOnly regular pref set", false);
  ExtensionTestMessageListener listener_incognito5(
      "changeDefaultOnly incognito listening", true);

  // changeIncognitoOnlyBack listeners.
  ExtensionTestMessageListener listener6(
      "changeIncognitoOnlyBack regular ready", true);
  ExtensionTestMessageListener listener_incognito6(
      "changeIncognitoOnlyBack incognito ready", true);
  ExtensionTestMessageListener listener7(
      "changeIncognitoOnlyBack regular listening", true);
  ExtensionTestMessageListener listener_incognito7(
      "changeIncognitoOnlyBack incognito pref set", false);

  // clearIncognito listeners.
  ExtensionTestMessageListener listener8(
      "clearIncognito regular ready", true);
  ExtensionTestMessageListener listener_incognito8(
      "clearIncognito incognito ready", true);
  ExtensionTestMessageListener listener9(
      "clearIncognito regular listening", true);
  ExtensionTestMessageListener listener_incognito9(
      "clearIncognito incognito pref cleared", false);

  // clearDefault listeners.
  ExtensionTestMessageListener listener10(
      "clearDefault regular ready", true);
  ExtensionTestMessageListener listener_incognito10(
      "clearDefault incognito ready", true);

  base::FilePath extension_data_dir =
      test_data_dir_.AppendASCII("preference").AppendASCII("onchange_split");
  ASSERT_TRUE(LoadExtensionIncognito(extension_data_dir));

  // Test 1 - changeDefault
  EXPECT_TRUE(listener1.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito1.WaitUntilSatisfied()); // Incognito ready
  listener1.Reply("ok");
  listener_incognito1.Reply("ok");

  // Test 2 - changeIncognitoOnly
  EXPECT_TRUE(listener2.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito2.WaitUntilSatisfied()); // Incognito ready
  EXPECT_TRUE(listener3.WaitUntilSatisfied()); // Regular listening
  listener2.Reply("ok");
  listener_incognito2.Reply("ok");
  // Incognito preference set -- notify the regular listener
  EXPECT_TRUE(listener_incognito3.WaitUntilSatisfied());
  listener3.Reply("ok");

  // Test 3 - changeDefaultOnly
  EXPECT_TRUE(listener4.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito4.WaitUntilSatisfied()); // Incognito ready
  EXPECT_TRUE(listener_incognito5.WaitUntilSatisfied()); // Incognito listening
  listener4.Reply("ok");
  listener_incognito4.Reply("ok");
  // Regular preference set - notify the incognito listener
  EXPECT_TRUE(listener5.WaitUntilSatisfied());
  listener_incognito5.Reply("ok");

  // Test 4 - changeIncognitoOnlyBack
  EXPECT_TRUE(listener6.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito6.WaitUntilSatisfied()); // Incognito ready
  EXPECT_TRUE(listener7.WaitUntilSatisfied()); // Regular listening
  listener6.Reply("ok");
  listener_incognito6.Reply("ok");
  // Incognito preference set -- notify the regular listener
  EXPECT_TRUE(listener_incognito7.WaitUntilSatisfied());
  listener7.Reply("ok");

  // Test 5 - clearIncognito
  EXPECT_TRUE(listener8.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito8.WaitUntilSatisfied()); // Incognito ready
  EXPECT_TRUE(listener9.WaitUntilSatisfied()); // Regular listening
  listener8.Reply("ok");
  listener_incognito8.Reply("ok");
  // Incognito preference cleared -- notify the regular listener
  EXPECT_TRUE(listener_incognito9.WaitUntilSatisfied());
  listener9.Reply("ok");

  // Test 6 - clearDefault
  EXPECT_TRUE(listener10.WaitUntilSatisfied()); // Regular ready
  EXPECT_TRUE(listener_incognito10.WaitUntilSatisfied()); // Incognito ready
  listener10.Reply("ok");
  listener_incognito10.Reply("ok");

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message();
}

#if defined(OS_WIN)  // http://crbug.com/477844
#define MAYBE_DataReductionProxy DISABLED_DataReductionProxy
#else
#define MAYBE_DataReductionProxy DataReductionProxy
#endif
IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, MAYBE_DataReductionProxy) {
  EXPECT_TRUE(RunExtensionTest("preference/data_reduction_proxy")) <<
      message_;
}
<|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/browser/ui/views/frame/app_non_client_frame_view_ash.h"

#include "ash/wm/workspace/frame_maximize_button.h"
#include "base/debug/stack_trace.h"
#include "chrome/browser/ui/views/frame/browser_frame.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "grit/ash_resources.h"
#include "grit/generated_resources.h"  // Accessibility names
#include "grit/theme_resources.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/non_client_view.h"

namespace {
// The number of pixels within the shadow to draw the buttons.
const int kShadowStart = 16;
// The size and close buttons are designed to overlap.
const int kButtonOverlap = 1;

// TODO(pkotwicz): Remove these constants once the IDR_AURA_FULLSCREEN_SHADOW
// resource is updated.
const int kShadowHeightStretch = -1;
}

class AppNonClientFrameViewAsh::ControlView
    : public views::View, public views::ButtonListener {
 public:
  explicit ControlView(AppNonClientFrameViewAsh* owner) :
      owner_(owner),
      close_button_(new views::ImageButton(this)),
      restore_button_(new ash::FrameMaximizeButton(this, owner_))
  {
    close_button_->SetAccessibleName(
        l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
    restore_button_->SetAccessibleName(
        l10n_util::GetStringUTF16(IDS_ACCNAME_MAXIMIZE));

    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();

    int control_base_resource_id = owner->browser_view()->IsOffTheRecord() ?
        IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_ACTIVE :
        IDR_AURA_WINDOW_HEADER_BASE_ACTIVE;
    control_base_ = rb.GetImageNamed(control_base_resource_id).ToImageSkia();
    shadow_ = rb.GetImageNamed(IDR_AURA_WINDOW_FULLSCREEN_SHADOW).ToImageSkia();

    AddChildView(close_button_);
    AddChildView(restore_button_);
  }

  virtual ~ControlView() {}

  virtual void Layout() OVERRIDE {
    restore_button_->SetPosition(gfx::Point(kShadowStart, 0));
    close_button_->SetPosition(gfx::Point(kShadowStart +
        restore_button_->width() - kButtonOverlap, 0));
  }

  virtual void ViewHierarchyChanged(bool is_add, View* parent,
                                    View* child) OVERRIDE {
    if (is_add && child == this) {
      SetButtonImages(restore_button_,
                      IDR_AURA_WINDOW_FULLSCREEN_RESTORE,
                      IDR_AURA_WINDOW_FULLSCREEN_RESTORE_H,
                      IDR_AURA_WINDOW_FULLSCREEN_RESTORE_P);
      restore_button_->SizeToPreferredSize();

      SetButtonImages(close_button_,
                      IDR_AURA_WINDOW_FULLSCREEN_CLOSE,
                      IDR_AURA_WINDOW_FULLSCREEN_CLOSE_H,
                      IDR_AURA_WINDOW_FULLSCREEN_CLOSE_P);
      close_button_->SizeToPreferredSize();
    }
  }

  virtual gfx::Size GetPreferredSize() OVERRIDE {
    return gfx::Size(shadow_->width(),
                     shadow_->height() + kShadowHeightStretch);
  }

  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    canvas->TileImageInt(*control_base_,
        restore_button_->x(),
        restore_button_->y(),
        restore_button_->width() - kButtonOverlap + close_button_->width(),
        restore_button_->height());

    views::View::OnPaint(canvas);

    canvas->DrawImageInt(*shadow_, 0, kShadowHeightStretch);
  }

  virtual void ButtonPressed(views::Button* sender,
                             const ui::Event& event) OVERRIDE {
    if (sender == close_button_) {
      owner_->frame()->Close();
    } else if (sender == restore_button_) {
      restore_button_->SetState(views::CustomButton::BS_NORMAL);
      owner_->frame()->Restore();
    }
  }

 private:
  // Sets images whose ids are passed in for each of the respective states
  // of |button|.
  void SetButtonImages(views::ImageButton* button, int normal_image_id,
                       int hot_image_id, int pushed_image_id) {
    ui::ThemeProvider* theme_provider = GetThemeProvider();
    button->SetImage(views::CustomButton::BS_NORMAL,
                     theme_provider->GetImageSkiaNamed(normal_image_id));
    button->SetImage(views::CustomButton::BS_HOT,
                     theme_provider->GetImageSkiaNamed(hot_image_id));
    button->SetImage(views::CustomButton::BS_PUSHED,
                     theme_provider->GetImageSkiaNamed(pushed_image_id));
  }

  AppNonClientFrameViewAsh* owner_;
  views::ImageButton* close_button_;
  views::ImageButton* restore_button_;
  const gfx::ImageSkia* control_base_;
  const gfx::ImageSkia* shadow_;

  DISALLOW_COPY_AND_ASSIGN(ControlView);
};

// Observer to detect when the browser frame widget closes so we can clean
// up our ControlView. Because we can be closed via a keyboard shortcut we
// are not guaranteed to run AppNonClientFrameView's Close() or Restore().
class AppNonClientFrameViewAsh::FrameObserver : public views::WidgetObserver {
 public:
  explicit FrameObserver(AppNonClientFrameViewAsh* owner) : owner_(owner) {}
  virtual ~FrameObserver() {}

  // views::WidgetObserver:
  virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE {
    owner_->CloseControlWidget();
  }

 private:
  AppNonClientFrameViewAsh* owner_;

  DISALLOW_COPY_AND_ASSIGN(FrameObserver);
};

// static
const char AppNonClientFrameViewAsh::kViewClassName[] =
    "AppNonClientFrameViewAsh";
// static
const char AppNonClientFrameViewAsh::kControlWindowName[] =
    "AppNonClientFrameViewAshControls";

AppNonClientFrameViewAsh::AppNonClientFrameViewAsh(
    BrowserFrame* frame, BrowserView* browser_view)
    : BrowserNonClientFrameView(frame, browser_view),
      control_view_(new ControlView(this)),
      control_widget_(NULL),
      frame_observer_(new FrameObserver(this)) {
  // This FrameView is always maximized so we don't want the window to have
  // resize borders.
  frame->GetNativeView()->set_hit_test_bounds_override_inner(gfx::Insets());
  // Watch for frame close so we can clean up the control widget.
  frame->AddObserver(frame_observer_.get());
  set_background(views::Background::CreateSolidBackground(SK_ColorBLACK));
  // Create the controls.
  control_widget_ = new views::Widget;
  views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
  params.parent = browser_view->GetNativeWindow();
  params.transparent = true;
  control_widget_->Init(params);
  control_widget_->SetContentsView(control_view_);
  aura::Window* window = control_widget_->GetNativeView();
  window->SetName(kControlWindowName);
  gfx::Rect control_bounds = GetControlBounds();
  window->SetBounds(control_bounds);
  control_widget_->Show();
}

AppNonClientFrameViewAsh::~AppNonClientFrameViewAsh() {
  frame()->RemoveObserver(frame_observer_.get());
  // This frame view can be replaced (and deleted) if the window is restored
  // via a keyboard shortcut like Alt-[.  Ensure we close the control widget.
  CloseControlWidget();
}

gfx::Rect AppNonClientFrameViewAsh::GetBoundsForClientView() const {
  return GetLocalBounds();
}

gfx::Rect AppNonClientFrameViewAsh::GetWindowBoundsForClientBounds(
    const gfx::Rect& client_bounds) const {
  return client_bounds;
}

int AppNonClientFrameViewAsh::NonClientHitTest(
    const gfx::Point& point) {
  return HTNOWHERE;
}

void AppNonClientFrameViewAsh::GetWindowMask(const gfx::Size& size,
                                             gfx::Path* window_mask) {
}

void AppNonClientFrameViewAsh::ResetWindowControls() {
}

void AppNonClientFrameViewAsh::UpdateWindowIcon() {
}

void AppNonClientFrameViewAsh::UpdateWindowTitle() {
}

gfx::Rect AppNonClientFrameViewAsh::GetBoundsForTabStrip(
    views::View* tabstrip) const {
  return gfx::Rect();
}

BrowserNonClientFrameView::TabStripInsets
AppNonClientFrameViewAsh::GetTabStripInsets(bool restored) const {
  return TabStripInsets();
}

int AppNonClientFrameViewAsh::GetThemeBackgroundXInset() const {
  return 0;
}

void AppNonClientFrameViewAsh::UpdateThrobber(bool running) {
}

std::string AppNonClientFrameViewAsh::GetClassName() const {
  return kViewClassName;
}

void AppNonClientFrameViewAsh::OnBoundsChanged(
    const gfx::Rect& previous_bounds) {
  if (control_widget_)
    control_widget_->GetNativeView()->SetBounds(GetControlBounds());
}

gfx::Rect AppNonClientFrameViewAsh::GetControlBounds() const {
  if (!control_view_)
    return gfx::Rect();
  gfx::Size preferred = control_view_->GetPreferredSize();
  return gfx::Rect(
      width() - preferred.width(), 0,
      preferred.width(), preferred.height());
}

void AppNonClientFrameViewAsh::CloseControlWidget() {
  if (control_widget_) {
    control_widget_->Close();
    control_widget_ = NULL;
  }
}
<commit_msg>Fixed hit area problem with full screen controls<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/ui/views/frame/app_non_client_frame_view_ash.h"

#include "ash/wm/workspace/frame_maximize_button.h"
#include "base/debug/stack_trace.h"
#include "chrome/browser/ui/views/frame/browser_frame.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "grit/ash_resources.h"
#include "grit/generated_resources.h"  // Accessibility names
#include "grit/theme_resources.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/non_client_view.h"

namespace {
// The number of pixels within the shadow to draw the buttons.
const int kShadowStart = 16;
// The size and close buttons are designed to overlap.
const int kButtonOverlap = 1;

// TODO(pkotwicz): Remove these constants once the IDR_AURA_FULLSCREEN_SHADOW
// resource is updated.
const int kShadowHeightStretch = -1;
}

class AppNonClientFrameViewAsh::ControlView
    : public views::View, public views::ButtonListener {
 public:
  explicit ControlView(AppNonClientFrameViewAsh* owner) :
      owner_(owner),
      close_button_(new views::ImageButton(this)),
      restore_button_(new ash::FrameMaximizeButton(this, owner_))
  {
    close_button_->SetAccessibleName(
        l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
    restore_button_->SetAccessibleName(
        l10n_util::GetStringUTF16(IDS_ACCNAME_MAXIMIZE));

    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();

    int control_base_resource_id = owner->browser_view()->IsOffTheRecord() ?
        IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_ACTIVE :
        IDR_AURA_WINDOW_HEADER_BASE_ACTIVE;
    control_base_ = rb.GetImageNamed(control_base_resource_id).ToImageSkia();
    shadow_ = rb.GetImageNamed(IDR_AURA_WINDOW_FULLSCREEN_SHADOW).ToImageSkia();

    AddChildView(close_button_);
    AddChildView(restore_button_);
  }

  virtual ~ControlView() {}

  virtual void Layout() OVERRIDE {
    restore_button_->SetPosition(gfx::Point(kShadowStart, 0));
    close_button_->SetPosition(gfx::Point(kShadowStart +
        restore_button_->width() - kButtonOverlap, 0));
  }

  virtual void ViewHierarchyChanged(bool is_add, View* parent,
                                    View* child) OVERRIDE {
    if (is_add && child == this) {
      SetButtonImages(restore_button_,
                      IDR_AURA_WINDOW_FULLSCREEN_RESTORE,
                      IDR_AURA_WINDOW_FULLSCREEN_RESTORE_H,
                      IDR_AURA_WINDOW_FULLSCREEN_RESTORE_P);
      restore_button_->SizeToPreferredSize();

      SetButtonImages(close_button_,
                      IDR_AURA_WINDOW_FULLSCREEN_CLOSE,
                      IDR_AURA_WINDOW_FULLSCREEN_CLOSE_H,
                      IDR_AURA_WINDOW_FULLSCREEN_CLOSE_P);
      close_button_->SizeToPreferredSize();
    }
  }

  virtual gfx::Size GetPreferredSize() OVERRIDE {
    return gfx::Size(shadow_->width(),
                     shadow_->height() + kShadowHeightStretch);
  }

  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    canvas->TileImageInt(*control_base_,
        restore_button_->x(),
        restore_button_->y(),
        restore_button_->width() - kButtonOverlap + close_button_->width(),
        restore_button_->height());

    views::View::OnPaint(canvas);

    canvas->DrawImageInt(*shadow_, 0, kShadowHeightStretch);
  }

  virtual void ButtonPressed(views::Button* sender,
                             const ui::Event& event) OVERRIDE {
    if (sender == close_button_) {
      owner_->frame()->Close();
    } else if (sender == restore_button_) {
      restore_button_->SetState(views::CustomButton::BS_NORMAL);
      owner_->frame()->Restore();
    }
  }

  // Returns the insets of the control which are only covered by the shadow.
  gfx::Insets GetShadowInsets() {
    return gfx::Insets(
        0,
        shadow_->width() - close_button_->width() - restore_button_->width(),
        shadow_->height() - close_button_->height(),
        0);
  }

 private:
  // Sets images whose ids are passed in for each of the respective states
  // of |button|.
  void SetButtonImages(views::ImageButton* button, int normal_image_id,
                       int hot_image_id, int pushed_image_id) {
    ui::ThemeProvider* theme_provider = GetThemeProvider();
    button->SetImage(views::CustomButton::BS_NORMAL,
                     theme_provider->GetImageSkiaNamed(normal_image_id));
    button->SetImage(views::CustomButton::BS_HOT,
                     theme_provider->GetImageSkiaNamed(hot_image_id));
    button->SetImage(views::CustomButton::BS_PUSHED,
                     theme_provider->GetImageSkiaNamed(pushed_image_id));
  }

  AppNonClientFrameViewAsh* owner_;
  views::ImageButton* close_button_;
  views::ImageButton* restore_button_;
  const gfx::ImageSkia* control_base_;
  const gfx::ImageSkia* shadow_;

  DISALLOW_COPY_AND_ASSIGN(ControlView);
};

// Observer to detect when the browser frame widget closes so we can clean
// up our ControlView. Because we can be closed via a keyboard shortcut we
// are not guaranteed to run AppNonClientFrameView's Close() or Restore().
class AppNonClientFrameViewAsh::FrameObserver : public views::WidgetObserver {
 public:
  explicit FrameObserver(AppNonClientFrameViewAsh* owner) : owner_(owner) {}
  virtual ~FrameObserver() {}

  // views::WidgetObserver:
  virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE {
    owner_->CloseControlWidget();
  }

 private:
  AppNonClientFrameViewAsh* owner_;

  DISALLOW_COPY_AND_ASSIGN(FrameObserver);
};

// static
const char AppNonClientFrameViewAsh::kViewClassName[] =
    "AppNonClientFrameViewAsh";
// static
const char AppNonClientFrameViewAsh::kControlWindowName[] =
    "AppNonClientFrameViewAshControls";

AppNonClientFrameViewAsh::AppNonClientFrameViewAsh(
    BrowserFrame* frame, BrowserView* browser_view)
    : BrowserNonClientFrameView(frame, browser_view),
      control_view_(new ControlView(this)),
      control_widget_(NULL),
      frame_observer_(new FrameObserver(this)) {
  // This FrameView is always maximized so we don't want the window to have
  // resize borders.
  frame->GetNativeView()->set_hit_test_bounds_override_inner(gfx::Insets());
  // Watch for frame close so we can clean up the control widget.
  frame->AddObserver(frame_observer_.get());
  set_background(views::Background::CreateSolidBackground(SK_ColorBLACK));
  // Create the controls.
  control_widget_ = new views::Widget;
  views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
  params.parent = browser_view->GetNativeWindow();
  params.transparent = true;
  control_widget_->Init(params);
  control_widget_->SetContentsView(control_view_);
  aura::Window* window = control_widget_->GetNativeView();
  window->SetName(kControlWindowName);
  // Need to exclude the shadow from the active control area.
  window->SetHitTestBoundsOverrideOuter(control_view_->GetShadowInsets(), 1);
  gfx::Rect control_bounds = GetControlBounds();
  window->SetBounds(control_bounds);
  control_widget_->Show();
}

AppNonClientFrameViewAsh::~AppNonClientFrameViewAsh() {
  frame()->RemoveObserver(frame_observer_.get());
  // This frame view can be replaced (and deleted) if the window is restored
  // via a keyboard shortcut like Alt-[.  Ensure we close the control widget.
  CloseControlWidget();
}

gfx::Rect AppNonClientFrameViewAsh::GetBoundsForClientView() const {
  return GetLocalBounds();
}

gfx::Rect AppNonClientFrameViewAsh::GetWindowBoundsForClientBounds(
    const gfx::Rect& client_bounds) const {
  return client_bounds;
}

int AppNonClientFrameViewAsh::NonClientHitTest(
    const gfx::Point& point) {
  return HTNOWHERE;
}

void AppNonClientFrameViewAsh::GetWindowMask(const gfx::Size& size,
                                             gfx::Path* window_mask) {
}

void AppNonClientFrameViewAsh::ResetWindowControls() {
}

void AppNonClientFrameViewAsh::UpdateWindowIcon() {
}

void AppNonClientFrameViewAsh::UpdateWindowTitle() {
}

gfx::Rect AppNonClientFrameViewAsh::GetBoundsForTabStrip(
    views::View* tabstrip) const {
  return gfx::Rect();
}

BrowserNonClientFrameView::TabStripInsets
AppNonClientFrameViewAsh::GetTabStripInsets(bool restored) const {
  return TabStripInsets();
}

int AppNonClientFrameViewAsh::GetThemeBackgroundXInset() const {
  return 0;
}

void AppNonClientFrameViewAsh::UpdateThrobber(bool running) {
}

std::string AppNonClientFrameViewAsh::GetClassName() const {
  return kViewClassName;
}

void AppNonClientFrameViewAsh::OnBoundsChanged(
    const gfx::Rect& previous_bounds) {
  if (control_widget_)
    control_widget_->GetNativeView()->SetBounds(GetControlBounds());
}

gfx::Rect AppNonClientFrameViewAsh::GetControlBounds() const {
  if (!control_view_)
    return gfx::Rect();
  gfx::Size preferred = control_view_->GetPreferredSize();
  return gfx::Rect(
      width() - preferred.width(), 0,
      preferred.width(), preferred.height());
}

void AppNonClientFrameViewAsh::CloseControlWidget() {
  if (control_widget_) {
    control_widget_->Close();
    control_widget_ = NULL;
  }
}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "Importer.h"
#include "common/sg/SceneGraph.h"
#include <memory>

/*! \file sg/module/Importer.cpp Defines the interface for writing
    file importers for the ospray::sg */

namespace ospray {
  namespace sg {

    struct ColorMap
    {
      ColorMap(float lo, float hi)
        : lo(lo), hi(hi)
      {
        assert(lo <= hi);
        // TODO: need a better color map here ...
        color.push_back(vec3f(0.f,0.f,0.f));
        color.push_back(vec3f(0.f,0.f,1.f));
        color.push_back(vec3f(0.f,1.f,0.f));
        color.push_back(vec3f(1.f,0.f,0.f));
        color.push_back(vec3f(1.f,1.f,0.f));
        color.push_back(vec3f(0.f,1.f,1.f));
        color.push_back(vec3f(1.f,0.f,1.f));
        color.push_back(vec3f(1.f,1.f,1.f));
      };

      vec4f colorFor(float f)
      {
        if (f <= lo) return vec4f(color.front(),1.f);
        if (f >= hi) return vec4f(color.back(),1.f);

        float r = ((f-lo) * color.size()) / (hi-lo);
        int idx = int(r);
        if (idx < 0) idx = 0;
        if (idx >= color.size()) idx = color.size()-1;

        vec3f c = color[idx] + (r-idx)*(color[idx+1]-color[idx]);
        return vec4f(c,1.f);
      }

      float lo, hi;
      std::vector<vec3f> color;
    };

    bool readOne(FILE *file, float *f, int N, bool ascii)
    {
      if (!ascii)
        return fread(f,sizeof(float),N,file) == N;

      // ascii:
      for (int i=0;i<N;i++) {
        int rc = fscanf(file,"%f",f+i);
        if (rc == 0) return (i == 0);
        fscanf(file,"\n");
      }
      return true;
    }

    // for now, let's hardcode the importers - should be moved to a
    // registry at some point ...
    void importFileType_points(std::shared_ptr<World> &world,
                               const FileName &url)
    {
      std::cout << "--------------------------------------------" << std::endl;
      std::cout << "#osp.sg: importer for 'points': " << url.str() << std::endl;

      FormatURL fu(url.str());
      PRINT(fu.fileName);

      // const std::string portHeader = strstr(url.str().c_str(),"://")+3;

      // const char *fileName = strstr(url.str().c_str(),"://")+3;
      PRINT(fu.fileName);
      FILE *file = fopen(fu.fileName.c_str(),"rb");
      if (!file)
        throw std::runtime_error("could not open file "+fu.fileName);

      // read the data vector
      PING;
      std::shared_ptr<DataVectorT<Spheres::Sphere,OSP_RAW>> sphereData
        = std::make_shared<DataVectorT<Spheres::Sphere,OSP_RAW>>();

      float radius = .1f;
      if (fu.hasArg("radius"))
        radius = std::stof(fu["radius"]);
      if (radius == 0.f)
        throw std::runtime_error("#sg.importPoints: could not parse radius ...");

      std::string format = "xyz";
      if (fu.hasArg("format"))
        format = fu["format"];

      bool ascii = fu.hasArg("ascii");

      /* for now, hard-coded sphere componetns to be in float format,
         so the number of chars in the format string is the num components */
      int numFloatsPerSphere = format.size();
      size_t xPos = format.find("x");
      size_t yPos = format.find("y");
      size_t zPos = format.find("z");
      size_t rPos = format.find("r");
      size_t sPos = format.find("s");

      if (xPos == std::string::npos)
        throw std::runtime_error("invalid points format: no x component");
      if (yPos == std::string::npos)
        throw std::runtime_error("invalid points format: no y component");
      if (zPos == std::string::npos)
        throw std::runtime_error("invalid points format: no z component");

      float f[numFloatsPerSphere];
      box3f bounds;

      std::vector<float> mappedScalarVector;
      float mappedScalarMin = +std::numeric_limits<float>::infinity();
      float mappedScalarMax = -std::numeric_limits<float>::infinity();

      while (readOne(file,f,numFloatsPerSphere,ascii)) {
        // read one more sphere ....
        Spheres::Sphere s;
        s.position.x = f[xPos];
        s.position.y = f[yPos];
        s.position.z = f[zPos];
        s.radius
          = (rPos == std::string::npos)
          ? radius
          : f[rPos];
        sphereData->v.push_back(s);
        bounds.extend(s.position-s.radius);
        bounds.extend(s.position+s.radius);

        if (sPos != std::string::npos) {
          mappedScalarVector.push_back(f[sPos]);
          mappedScalarMin = std::min(mappedScalarMin,f[sPos]);
          mappedScalarMax = std::max(mappedScalarMax,f[sPos]);
        }
      }
      fclose(file);

      // create the node
      NodeHandle sphereObject = createNode("spheres","Spheres");

      // iw - note that 'add' sounds wrong here, but that's the way
      // the current scene graph works - 'adding' that node (which
      // happens to have the right name) will essentially replace the
      // old value of that node, and thereby assign the 'data' field
      sphereData->setName("sphereData");
      sphereObject->add(sphereData); //["data"]->setValue(data);

      if (!mappedScalarVector.empty()) {
        std::cout << "#osp.sg: creating color map for points data ..." << std::endl;
        ColorMap cm(mappedScalarMin,mappedScalarMax);
        std::shared_ptr<DataVectorT<vec4f,OSP_RAW>> colorData
          = std::make_shared<DataVectorT<vec4f,OSP_RAW>>();
        for (int i=0;i<mappedScalarVector.size();i++)
          colorData->v.push_back(cm.colorFor(mappedScalarVector[i]));
        colorData->setName("colorData");
        sphereObject->add(colorData);
      }

      std::cout << "#osp.sg: imported " << prettyNumber(sphereData->v.size())
                << " points, bounds = " << bounds << std::endl;;
      NodeHandle(world) += sphereObject;
    }

  }// ::ospray::sg
}// ::ospray

<commit_msg>- bugfix in color map code - better 'cool to warm' color map<commit_after>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "Importer.h"
#include "common/sg/SceneGraph.h"
#include <memory>

/*! \file sg/module/Importer.cpp Defines the interface for writing
    file importers for the ospray::sg */

namespace ospray {
  namespace sg {

    struct ColorMap
    {
      ColorMap(float lo, float hi)
        : lo(lo), hi(hi)
      {
        assert(lo <= hi);

        // TODO: need a better color map here ...
        // color.push_back(vec3f(0.f,0.f,0.f));
        // color.push_back(vec3f(0.f,0.f,1.f));
        // color.push_back(vec3f(0.f,1.f,0.f));
        // color.push_back(vec3f(1.f,0.f,0.f));
        // color.push_back(vec3f(1.f,1.f,0.f));
        // color.push_back(vec3f(0.f,1.f,1.f));
        // color.push_back(vec3f(1.f,0.f,1.f));
        // color.push_back(vec3f(1.f,1.f,1.f));

        // from old qtivewre: "cool to warm"
        color.push_back(ospcommon::vec3f(0.231373  , 0.298039    , 0.752941    ));
        color.push_back(ospcommon::vec3f(0.865003  , 0.865003    , 0.865003    ));
        color.push_back(ospcommon::vec3f(0.705882  , 0.0156863   , 0.14902     ));
      };

      vec4f colorFor(float f)
      {
        if (f <= lo) return vec4f(color.front(),1.f);
        if (f >= hi) return vec4f(color.back(),1.f);

        float r = ((f-lo) * (color.size()-1)) / (hi-lo);
        int idx = int(r);
        if (idx < 0) idx = 0;
        if (idx >= color.size()) idx = color.size()-2;

        vec3f c = color[idx] + (r-idx)*(color[idx+1]-color[idx]);
        return vec4f(c,1.f);
      }

      float lo, hi;
      std::vector<vec3f> color;
    };

    bool readOne(FILE *file, float *f, int N, bool ascii)
    {
      if (!ascii)
        return fread(f,sizeof(float),N,file) == N;

      // ascii:
      for (int i=0;i<N;i++) {
        int rc = fscanf(file,"%f",f+i);
        if (rc == 0) return (i == 0);
        fscanf(file,"\n");
      }
      return true;
    }

    // for now, let's hardcode the importers - should be moved to a
    // registry at some point ...
    void importFileType_points(std::shared_ptr<World> &world,
                               const FileName &url)
    {
      std::cout << "--------------------------------------------" << std::endl;
      std::cout << "#osp.sg: importer for 'points': " << url.str() << std::endl;

      FormatURL fu(url.str());
      PRINT(fu.fileName);

      // const std::string portHeader = strstr(url.str().c_str(),"://")+3;

      // const char *fileName = strstr(url.str().c_str(),"://")+3;
      PRINT(fu.fileName);
      FILE *file = fopen(fu.fileName.c_str(),"rb");
      if (!file)
        throw std::runtime_error("could not open file "+fu.fileName);

      // read the data vector
      PING;
      std::shared_ptr<DataVectorT<Spheres::Sphere,OSP_RAW>> sphereData
        = std::make_shared<DataVectorT<Spheres::Sphere,OSP_RAW>>();

      float radius = .1f;
      if (fu.hasArg("radius"))
        radius = std::stof(fu["radius"]);
      if (radius == 0.f)
        throw std::runtime_error("#sg.importPoints: could not parse radius ...");

      std::string format = "xyz";
      if (fu.hasArg("format"))
        format = fu["format"];

      bool ascii = fu.hasArg("ascii");

      /* for now, hard-coded sphere componetns to be in float format,
         so the number of chars in the format string is the num components */
      int numFloatsPerSphere = format.size();
      size_t xPos = format.find("x");
      size_t yPos = format.find("y");
      size_t zPos = format.find("z");
      size_t rPos = format.find("r");
      size_t sPos = format.find("s");

      if (xPos == std::string::npos)
        throw std::runtime_error("invalid points format: no x component");
      if (yPos == std::string::npos)
        throw std::runtime_error("invalid points format: no y component");
      if (zPos == std::string::npos)
        throw std::runtime_error("invalid points format: no z component");

      float f[numFloatsPerSphere];
      box3f bounds;

      std::vector<float> mappedScalarVector;
      float mappedScalarMin = +std::numeric_limits<float>::infinity();
      float mappedScalarMax = -std::numeric_limits<float>::infinity();

      while (readOne(file,f,numFloatsPerSphere,ascii)) {
        // read one more sphere ....
        Spheres::Sphere s;
        s.position.x = f[xPos];
        s.position.y = f[yPos];
        s.position.z = f[zPos];
        s.radius
          = (rPos == std::string::npos)
          ? radius
          : f[rPos];
        sphereData->v.push_back(s);
        bounds.extend(s.position-s.radius);
        bounds.extend(s.position+s.radius);

        if (sPos != std::string::npos) {
          mappedScalarVector.push_back(f[sPos]);
          mappedScalarMin = std::min(mappedScalarMin,f[sPos]);
          mappedScalarMax = std::max(mappedScalarMax,f[sPos]);
        }
      }
      fclose(file);

      // create the node
      NodeHandle sphereObject = createNode("spheres","Spheres");

      // iw - note that 'add' sounds wrong here, but that's the way
      // the current scene graph works - 'adding' that node (which
      // happens to have the right name) will essentially replace the
      // old value of that node, and thereby assign the 'data' field
      sphereData->setName("sphereData");
      sphereObject->add(sphereData); //["data"]->setValue(data);

      if (!mappedScalarVector.empty()) {
        std::cout << "#osp.sg: creating color map for points data ..." << std::endl;
        ColorMap cm(mappedScalarMin,mappedScalarMax);
        std::shared_ptr<DataVectorT<vec4f,OSP_RAW>> colorData
          = std::make_shared<DataVectorT<vec4f,OSP_RAW>>();
        for (int i=0;i<mappedScalarVector.size();i++)
          colorData->v.push_back(cm.colorFor(mappedScalarVector[i]));
        colorData->setName("colorData");
        sphereObject->add(colorData);
      }

      std::cout << "#osp.sg: imported " << prettyNumber(sphereData->v.size())
                << " points, bounds = " << bounds << std::endl;;
      NodeHandle(world) += sphereObject;
    }

  }// ::ospray::sg
}// ::ospray

<|endoftext|>


<commit_before>/*
 * Copyright 2019,
 * Olivier Stasse,
 *
 * CNRS/AIST
 *
 */

#include <iostream>
#include <sot/core/debug.hh>

#ifndef WIN32
#include <unistd.h>
#endif

using namespace std;

#include <boost/test/unit_test.hpp>
#include <dynamic-graph/entity.h>
#include <dynamic-graph/factory.h>
#include <sot/core/device.hh>
#include <sstream>

using namespace dynamicgraph;
using namespace dynamicgraph::sot;

class TestDevice : public dg::sot::Device {
public:
  TestDevice(const std::string &RobotName) : Device(RobotName) {
    timestep_ = 0.001;
  }
  ~TestDevice() {}
};

BOOST_AUTO_TEST_CASE(test_device) {

  TestDevice aDevice(std::string("simple_humanoid"));

  /// Fix constant vector for the control entry in position
  dg::Vector aStateVector(38);
  dg::Vector aVelocityVector(38);
  dg::Vector aLowerVelBound(38), anUpperVelBound(38);
  dg::Vector aLowerBound(38), anUpperBound(38);
  dg::Vector anAccelerationVector(38);
  dg::Vector aControlVector(38);

  for (unsigned int i = 0; i < 38; i++) {
    // Specify lower velocity bound
    aLowerVelBound[i] = -3.14;
    // Specify lower position bound
    aLowerBound[i]=-3.14;
    // Specify state vector
    aStateVector[i] = 0.1;
    // Specify upper velocity bound
    anUpperVelBound[i] = 3.14;
    // Specify upper position bound
    anUpperBound[i]=3.14;
    // Specify control vector
    aControlVector(i)= 0.1;
  }
  /// Specify state size
  aDevice.setStateSize(38);
  /// Specify state bounds
  aDevice.setPositionBounds(aLowerBound,anUpperBound);
  /// Specify velocity size
  aDevice.setVelocitySize(38);
  /// Specify velocity
  aDevice.setVelocity(aStateVector);
  /// Specify velocity bounds
  aDevice.setVelocityBounds(aLowerVelBound, anUpperVelBound);
  /// Specify current state value
  aDevice.setState(aStateVector); // entry signal in position
  /// Specify constant control value
  aDevice.controlSIN.setConstant(aControlVector);

  for (unsigned int i = 0; i < 2000; i++) {
    double dt=0.001;
    aDevice.increment(dt);
    if (i == 0)
    {
      aDevice.stateSOUT.get(std::cout);
      std::ostringstream anoss;
      aDevice.stateSOUT.get(anoss);
      for (unsigned int i = 0; i < 38; i++)
        aControlVector[i]= 0.5;
    }
    if (i == 1)
    {
      aDevice.stateSOUT.get(std::cout);
      std::ostringstream anoss;
      aDevice.stateSOUT.get(anoss);
    }
  }

  aDevice.display(std::cout);
  aDevice.cmdDisplay();
}
<commit_msg>[unitTesting] Improve test_device<commit_after>/*
 * Copyright 2019,
 * Olivier Stasse,
 *
 * CNRS/AIST
 *
 */

#include <pinocchio/multibody/liegroup/special-euclidean.hpp>

#include <iostream>
#include <sot/core/debug.hh>

#ifndef WIN32
#include <unistd.h>
#endif

using namespace std;

#include <boost/test/unit_test.hpp>
#include <dynamic-graph/entity.h>
#include <dynamic-graph/factory.h>
#include <sot/core/device.hh>
#include <sstream>

using namespace dynamicgraph;
using namespace dynamicgraph::sot;

class TestDevice : public dg::sot::Device {
public:
  TestDevice(const std::string &RobotName) : Device(RobotName) {
    timestep_ = 0.001;
  }
  ~TestDevice() {}
};

BOOST_AUTO_TEST_CASE(test_device) {

  TestDevice aDevice(std::string("simple_humanoid"));

  /// Fix constant vector for the control entry in position
  dg::Vector aStateVector(38);
  dg::Vector aVelocityVector(38);
  dg::Vector aLowerVelBound(38), anUpperVelBound(38);
  dg::Vector aLowerBound(38), anUpperBound(38);
  dg::Vector anAccelerationVector(38);
  dg::Vector aControlVector(38);

  for (unsigned int i = 0; i < 38; i++) {
    // Specify lower velocity bound
    aLowerVelBound[i] = -3.14;
    // Specify lower position bound
    aLowerBound[i]=-3.14;
    // Specify state vector
    aStateVector[i] = 0.1;
    // Specify upper velocity bound
    anUpperVelBound[i] = 3.14;
    // Specify upper position bound
    anUpperBound[i]=3.14;
    // Specify control vector
    aControlVector(i)= 0.1;
  }

  dg::Vector expected = aStateVector; // backup initial state vector

  /// Specify state size
  aDevice.setStateSize(38);
  /// Specify state bounds
  aDevice.setPositionBounds(aLowerBound,anUpperBound);
  /// Specify velocity size
  aDevice.setVelocitySize(38);
  /// Specify velocity
  aDevice.setVelocity(aStateVector);
  /// Specify velocity bounds
  aDevice.setVelocityBounds(aLowerVelBound, anUpperVelBound);
  /// Specify current state value
  aDevice.setState(aStateVector); // entry signal in position
  /// Specify constant control value
  aDevice.controlSIN.setConstant(aControlVector);

  const double dt = 0.001;
  const unsigned int N = 2000;
  for (unsigned int i = 0; i < N; i++) {
    aDevice.increment(dt);
    if (i == 0)
    {
      aDevice.stateSOUT.get(std::cout);
      std::ostringstream anoss;
      aDevice.stateSOUT.get(anoss);
    }
    if (i == 1)
    {
      aDevice.stateSOUT.get(std::cout);
      std::ostringstream anoss;
      aDevice.stateSOUT.get(anoss);
    }
  }

  aDevice.display(std::cout);
  aDevice.cmdDisplay();

  // verify correct integration
  typedef pinocchio::SpecialEuclideanOperationTpl<3, double> SE3;
  Eigen::Matrix<double, 7, 1> qin, qout;
  qin.head<3>() = expected.head<3>();

  Eigen::QuaternionMapd quat (qin.tail<4>().data());
  quat = Eigen::AngleAxisd(expected(5), Eigen::Vector3d::UnitZ())
       * Eigen::AngleAxisd(expected(4), Eigen::Vector3d::UnitY())
       * Eigen::AngleAxisd(expected(3), Eigen::Vector3d::UnitX());

  const double T = dt*N;
  Eigen::Matrix<double, 6, 1> control = aControlVector.head<6>()*T;
  SE3().integrate (qin, control, qout);

  // Manual integration
  expected.head<3>() = qout.head<3>();
  expected.segment<3>(3) = Eigen::QuaternionMapd(qout.tail<4>().data()).toRotationMatrix().eulerAngles(2,1,0).reverse();
  for(int i=6; i<expected.size(); i++)
    expected[i] = 0.3;

  std::cout << expected.transpose() << std::endl;
  std::cout << aDevice.stateSOUT(N).transpose() << std::endl;

  BOOST_CHECK(aDevice.stateSOUT(N).isApprox(expected));
}
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "AvatarModule.h"
#include "AvatarEditing/AvatarEditor.h"
#include "InputAPI.h"
#include "Scene.h"
#include "SceneAPI.h"
#include "AssetAPI.h"
#include "GenericAssetFactory.h"
#include "NullAssetFactory.h"
#include "AvatarDescAsset.h"
#include "ConsoleAPI.h"
#include "IComponentFactory.h"

#include "EntityComponent/EC_Avatar.h"

namespace Avatar
{
    AvatarModule::AvatarModule()
    :IModule("Avatar")
    {
    }

    AvatarModule::~AvatarModule()
    {
    }

    void AvatarModule::Load()
    {
        framework_->Scene()->RegisterComponentFactory(ComponentFactoryPtr(new GenericComponentFactory<EC_Avatar>));

        ///\todo This doesn't need to be loaded in headless server mode.
        // Note: need to register in Initialize(), because in PostInitialize() AssetModule refreshes the local asset storages, and that
        // would result in inability to create any avatar assets in unloaded state
        if (!framework_->IsHeadless())
            framework_->Asset()->RegisterAssetTypeFactory(AssetTypeFactoryPtr(new GenericAssetFactory<AvatarDescAsset>("Avatar")));
        else
            framework_->Asset()->RegisterAssetTypeFactory(AssetTypeFactoryPtr(new NullAssetFactory("Avatar")));
    }

    void AvatarModule::Initialize()
    {
        avatar_editor_ = AvatarEditorPtr(new AvatarEditor(this));
    }

    void AvatarModule::PostInitialize()
    {
        avatar_context_ = GetFramework()->Input()->RegisterInputContext("Avatar", 100);
        if (avatar_context_)
        {
            connect(avatar_context_.get(), SIGNAL(KeyPressed(KeyEvent*)), SLOT(KeyPressed(KeyEvent*)));
            connect(avatar_context_.get(), SIGNAL(KeyReleased(KeyEvent*)), SLOT(KeyReleased(KeyEvent*)));
        }

        framework_->Console()->RegisterCommand("editavatar",
            "Edits the avatar in a specific entity. Usage: editavatar(entityname)",
            this, SLOT(EditAvatar(const QString &)));
    }

    void AvatarModule::Uninitialize()
    {
        avatar_handler_.reset();
        avatar_controllable_.reset();
        avatar_editor_.reset();
    }

    void AvatarModule::Update(f64 frametime)
    {
    }

    void AvatarModule::KeyPressed(KeyEvent *key)
    {
    }

    void AvatarModule::KeyReleased(KeyEvent *key)
    {

    }

    void AvatarModule::EditAvatar(const QString &entityName)
    {
        ScenePtr scene = framework_->Scene()->GetDefaultScene();
        if (!scene)
            return;// ConsoleResultFailure("No scene");
        EntityPtr entity = scene->GetEntityByName(entityName);
        if (!entity)
            return;// ConsoleResultFailure("No such entity " + entityName.toStdString());

        /// \todo Clone the avatar asset for editing
        /// \todo Allow avatar asset editing without an avatar entity in the scene
        avatar_editor_->SetEntityToEdit(entity);

        if (avatar_editor_)
            avatar_editor_->show();
    }
}

extern "C"
{
__declspec(dllexport) void TundraPluginMain(Framework *fw)
{
    Framework::SetInstance(fw); // Inside this DLL, remember the pointer to the global framework object.
    IModule *module = new Avatar::AvatarModule();
    fw->RegisterModule(module);
}
}
<commit_msg>Fixed previous avatarmodule refactors to build properly.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "AvatarModule.h"
#include "AvatarEditor.h"
#include "InputAPI.h"
#include "Scene.h"
#include "SceneAPI.h"
#include "AssetAPI.h"
#include "GenericAssetFactory.h"
#include "NullAssetFactory.h"
#include "AvatarDescAsset.h"
#include "ConsoleAPI.h"
#include "IComponentFactory.h"

#include "EC_Avatar.h"

namespace Avatar
{
    AvatarModule::AvatarModule()
    :IModule("Avatar")
    {
    }

    AvatarModule::~AvatarModule()
    {
    }

    void AvatarModule::Load()
    {
        framework_->Scene()->RegisterComponentFactory(ComponentFactoryPtr(new GenericComponentFactory<EC_Avatar>));

        ///\todo This doesn't need to be loaded in headless server mode.
        // Note: need to register in Initialize(), because in PostInitialize() AssetModule refreshes the local asset storages, and that
        // would result in inability to create any avatar assets in unloaded state
        if (!framework_->IsHeadless())
            framework_->Asset()->RegisterAssetTypeFactory(AssetTypeFactoryPtr(new GenericAssetFactory<AvatarDescAsset>("Avatar")));
        else
            framework_->Asset()->RegisterAssetTypeFactory(AssetTypeFactoryPtr(new NullAssetFactory("Avatar")));
    }

    void AvatarModule::Initialize()
    {
        avatar_editor_ = AvatarEditorPtr(new AvatarEditor(this));
    }

    void AvatarModule::PostInitialize()
    {
        avatar_context_ = GetFramework()->Input()->RegisterInputContext("Avatar", 100);
        if (avatar_context_)
        {
            connect(avatar_context_.get(), SIGNAL(KeyPressed(KeyEvent*)), SLOT(KeyPressed(KeyEvent*)));
            connect(avatar_context_.get(), SIGNAL(KeyReleased(KeyEvent*)), SLOT(KeyReleased(KeyEvent*)));
        }

        framework_->Console()->RegisterCommand("editavatar",
            "Edits the avatar in a specific entity. Usage: editavatar(entityname)",
            this, SLOT(EditAvatar(const QString &)));
    }

    void AvatarModule::Uninitialize()
    {
        avatar_handler_.reset();
        avatar_controllable_.reset();
        avatar_editor_.reset();
    }

    void AvatarModule::Update(f64 frametime)
    {
    }

    void AvatarModule::KeyPressed(KeyEvent *key)
    {
    }

    void AvatarModule::KeyReleased(KeyEvent *key)
    {

    }

    void AvatarModule::EditAvatar(const QString &entityName)
    {
        ScenePtr scene = framework_->Scene()->GetDefaultScene();
        if (!scene)
            return;// ConsoleResultFailure("No scene");
        EntityPtr entity = scene->GetEntityByName(entityName);
        if (!entity)
            return;// ConsoleResultFailure("No such entity " + entityName.toStdString());

        /// \todo Clone the avatar asset for editing
        /// \todo Allow avatar asset editing without an avatar entity in the scene
        avatar_editor_->SetEntityToEdit(entity);

        if (avatar_editor_)
            avatar_editor_->show();
    }
}

extern "C"
{
__declspec(dllexport) void TundraPluginMain(Framework *fw)
{
    Framework::SetInstance(fw); // Inside this DLL, remember the pointer to the global framework object.
    IModule *module = new Avatar::AvatarModule();
    fw->RegisterModule(module);
}
}
<|endoftext|>