<commit_before>/*
   Copyright 2012 Tzvetan Mikov <tmikov@gmail.com>
   All rights reserved.

   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.
*/

#ifndef FASTINPUT_HPP
#define	FASTINPUT_HPP

#include "base.hpp"

#include "boost/scoped_array.hpp"

class io_error : public std::runtime_error
{
public:
  io_error ( const std::string & what ) : runtime_error( what ) {};
};

template<typename ELEM, typename RES, RES _EOF>
class FastInput
{
protected:
  ELEM * m_buf,  * m_head, * m_tail;
  off_t m_bufOffset;

  FastInput ( ELEM * buf )
  {
    m_buf = m_head = m_tail = buf;
    m_bufOffset = 0;
  }

public:
  static const RES EOFVAL = _EOF;

  virtual ~FastInput () {};

  __forceinline RES get ()
  {
    if (likely(m_head != m_tail))
      return *m_head++;
    else
      return slowGet();
  }

  __forceinline size_t read ( ELEM * dest, size_t count )
  {
    if (likely(m_tail - m_head >= count))
    {
      std::memcpy( dest, m_head, count*sizeof(ELEM) );
      m_head += count;
      return count;
    }
    else
      return slowRead( dest, count );
  }

  __forceinline RES peek ()
  {
    if (likely(m_head != m_tail))
      return *m_head;
    else
      return slowPeek();
  }

  size_t available () const { return m_tail - m_head; }
  const ELEM * head () const { return m_head; }
  const ELEM * tail () const { return m_tail; }

  void advance ( size_t len )
  {
    assert( len <= m_tail - m_head );
    m_head += len;
  }

  /**
   * Return the offset of the next character (head)
   */
  off_t offset () const
  {
    return m_bufOffset + (m_head - m_buf);
  }

  virtual size_t fillBuffer () = 0;

private:
  RES    slowGet ();
  RES    slowPeek ();
  size_t slowRead ( ELEM * dest, size_t count );
};

template<typename ELEM, typename RES, RES _EOF>
__neverinline RES FastInput<ELEM,RES,_EOF>::slowGet ()
{
  return fillBuffer() != 0 ? *m_head++ : EOFVAL;
}

template<typename ELEM, typename RES, RES _EOF>
__neverinline RES FastInput<ELEM,RES,_EOF>::slowPeek ()
{
  return fillBuffer() != 0 ? *m_head : EOFVAL;
}

template<typename ELEM, typename RES, RES _EOF>
__neverinline size_t FastInput<ELEM,RES,_EOF>::slowRead ( ELEM * dest, size_t count )
{
  assert( count != 0 );
  size_t res = 0;
  for(;;)
  {
    size_t len = std::min( available(), count );
    std::memcpy( dest, m_head, len * sizeof(ELEM) );
    dest += len;
    m_head += len;
    res += len;
    count -= len;
    if (!count || !fillBuffer())
      break;
  }
  return res;
}

typedef FastInput<unsigned char,int,-1> FastCharInput;

class CharBufInput : public FastCharInput
{
public:
  CharBufInput ( const char * str, size_t len );
  CharBufInput ( const char * str );
  CharBufInput ( const std::string & str );
  virtual size_t fillBuffer ();

  /**
   * Puts back one character. Must only be used for actual characters that have been read and must
   * always out back the character that was read.
   * @param x The character to put back
   */
  void unget ( int x )
  {
    assert( m_head > m_buf && (int)*(m_head-1) == x );
    --m_head;
  }
};

template<typename ELEM, typename RES, RES _EOF>
class BufferedInput : public FastInput<ELEM,RES,_EOF>
{
  typedef FastInput<ELEM,RES,_EOF> Super;

  boost::scoped_array<ELEM> m_bufCleaner;

protected:
  static const unsigned DEFAULT_BUFSIZE = 4096;
  size_t m_bufSize;

  BufferedInput ( size_t bufSize = DEFAULT_BUFSIZE )
    : Super( new ELEM[bufSize] ), m_bufCleaner( Super::m_buf ), m_bufSize(bufSize)
  {
    assert( bufSize > UNGET_LIMIT );
  };

public:
  static const unsigned UNGET_LIMIT = 8;

  /**
   * Puts back one character. No more than {@code UNGET_LIMIT} characters can
   * be put back
   * @param x The character to put back
   */
  __forceinline void unget ( RES x )
  {
    assert( Super::m_head > Super::m_buf );
    *--Super::m_head = (ELEM)x;
  }

  virtual size_t fillBuffer ();
protected:
  /**
   * Read up to len bytes into m_tail and advance m_tail. Throw io_error on error.
   * @param len
   */
  virtual void doRead ( size_t len ) = 0;
};

template<typename ELEM, typename RES, RES _EOF>
size_t BufferedInput<ELEM,RES,_EOF>::fillBuffer ()
{
  if (Super::m_head < Super::m_tail) // Do we have unread data?
  {
    if (Super::m_head > Super::m_buf + UNGET_LIMIT) // Do we need to shift?
    {
      Super::m_bufOffset += Super::m_head - Super::m_buf - UNGET_LIMIT;
      size_t avail;
      memmove( Super::m_buf + UNGET_LIMIT, Super::m_head, (avail = Super::m_tail - Super::m_head)*sizeof(ELEM) );
      Super::m_head = Super::m_buf + UNGET_LIMIT;
      Super::m_tail = Super::m_head + avail;
    }
  }
  else
  {
    Super::m_bufOffset += Super::m_head - Super::m_buf - UNGET_LIMIT;
    Super::m_head = Super::m_tail = Super::m_buf + UNGET_LIMIT;
  }

  doRead( Super::m_buf + m_bufSize - Super::m_tail );

  return Super::available();
}

typedef BufferedInput<unsigned char,int,-1> BufferedCharInput;

#endif	/* FASTINPUT_HPP */

<commit_msg>FastInput.hpp: edits to remove bening warnings and trailing spaces<commit_after>/*
   Copyright 2012 Tzvetan Mikov <tmikov@gmail.com>
   All rights reserved.

   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.
*/

#ifndef FASTINPUT_HPP
#define	FASTINPUT_HPP

#include "base.hpp"

#include "boost/scoped_array.hpp"

class io_error : public std::runtime_error
{
public:
  io_error ( const std::string & what ) : runtime_error( what ) {};
};

template<typename ELEM, typename RES, RES _EOF>
class FastInput
{
protected:
  ELEM * m_buf,  * m_head, * m_tail;
  off_t m_bufOffset;

  FastInput ( ELEM * buf )
  {
    m_buf = m_head = m_tail = buf;
    m_bufOffset = 0;
  }

public:
  static const RES EOFVAL = _EOF;

  virtual ~FastInput () {};

  __forceinline RES get ()
  {
    if (likely(m_head != m_tail))
      return *m_head++;
    else
      return slowGet();
  }

  __forceinline size_t read ( ELEM * dest, size_t count )
  {
    if (likely(m_tail - m_head >= count))
    {
      std::memcpy( dest, m_head, count*sizeof(ELEM) );
      m_head += count;
      return count;
    }
    else
      return slowRead( dest, count );
  }

  __forceinline RES peek ()
  {
    if (likely(m_head != m_tail))
      return *m_head;
    else
      return slowPeek();
  }

  size_t available () const { return m_tail - m_head; }
  const ELEM * head () const { return m_head; }
  const ELEM * tail () const { return m_tail; }

  void advance ( size_t len )
  {
    assert( (ssize_t)len <= m_tail - m_head );
    m_head += len;
  }

  /**
   * Return the offset of the next character (head)
   */
  off_t offset () const
  {
    return m_bufOffset + (m_head - m_buf);
  }

  virtual size_t fillBuffer () = 0;

private:
  RES    slowGet ();
  RES    slowPeek ();
  size_t slowRead ( ELEM * dest, size_t count );
};

template<typename ELEM, typename RES, RES _EOF>
__neverinline RES FastInput<ELEM,RES,_EOF>::slowGet ()
{
  return fillBuffer() != 0 ? *m_head++ : EOFVAL;
}

template<typename ELEM, typename RES, RES _EOF>
__neverinline RES FastInput<ELEM,RES,_EOF>::slowPeek ()
{
  return fillBuffer() != 0 ? *m_head : EOFVAL;
}

template<typename ELEM, typename RES, RES _EOF>
__neverinline size_t FastInput<ELEM,RES,_EOF>::slowRead ( ELEM * dest, size_t count )
{
  assert( count != 0 );
  size_t res = 0;
  for(;;)
  {
    size_t len = std::min( available(), count );
    std::memcpy( dest, m_head, len * sizeof(ELEM) );
    dest += len;
    m_head += len;
    res += len;
    count -= len;
    if (!count || !fillBuffer())
      break;
  }
  return res;
}

typedef FastInput<unsigned char,int,-1> FastCharInput;

class CharBufInput : public FastCharInput
{
public:
  CharBufInput ( const char * str, size_t len );
  CharBufInput ( const char * str );
  CharBufInput ( const std::string & str );
  virtual size_t fillBuffer ();

  /**
   * Puts back one character. Must only be used for actual characters that have been read and must
   * always out back the character that was read.
   * @param x The character to put back
   */
  void unget ( int x )
  {
    assert( m_head > m_buf && (int)*(m_head-1) == x );
    --m_head;
  }
};

template<typename ELEM, typename RES, RES _EOF>
class BufferedInput : public FastInput<ELEM,RES,_EOF>
{
  typedef FastInput<ELEM,RES,_EOF> Super;

  boost::scoped_array<ELEM> m_bufCleaner;

protected:
  static const unsigned DEFAULT_BUFSIZE = 4096;
  size_t m_bufSize;

  BufferedInput ( size_t bufSize = DEFAULT_BUFSIZE )
    : Super( new ELEM[bufSize] ), m_bufCleaner( Super::m_buf ), m_bufSize(bufSize)
  {
    assert( bufSize > UNGET_LIMIT );
  };

public:
  static const unsigned UNGET_LIMIT = 8;

  /**
   * Puts back one character. No more than {@code UNGET_LIMIT} characters can
   * be put back
   * @param x The character to put back
   */
  __forceinline void unget ( RES x )
  {
    assert( Super::m_head > Super::m_buf );
    *--Super::m_head = (ELEM)x;
  }

  virtual size_t fillBuffer ();
protected:
  /**
   * Read up to len bytes into m_tail and advance m_tail. Throw io_error on error.
   * @param len
   */
  virtual void doRead ( size_t len ) = 0;
};

template<typename ELEM, typename RES, RES _EOF>
size_t BufferedInput<ELEM,RES,_EOF>::fillBuffer ()
{
  if (Super::m_head < Super::m_tail) // Do we have unread data?
  {
    if (Super::m_head > Super::m_buf + UNGET_LIMIT) // Do we need to shift?
    {
      Super::m_bufOffset += Super::m_head - Super::m_buf - UNGET_LIMIT;
      size_t avail;
      memmove( Super::m_buf + UNGET_LIMIT, Super::m_head, (avail = Super::m_tail - Super::m_head)*sizeof(ELEM) );
      Super::m_head = Super::m_buf + UNGET_LIMIT;
      Super::m_tail = Super::m_head + avail;
    }
  }
  else
  {
    Super::m_bufOffset += Super::m_head - Super::m_buf - UNGET_LIMIT;
    Super::m_head = Super::m_tail = Super::m_buf + UNGET_LIMIT;
  }

  doRead( Super::m_buf + m_bufSize - Super::m_tail );

  return Super::available();
}

typedef BufferedInput<unsigned char,int,-1> BufferedCharInput;

#endif	/* FASTINPUT_HPP */

<|endoftext|>


<commit_before>// Copyright 2014 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/extensions/extension_action_view_controller.h"

#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/api/commands/command_service.h"
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_view.h"
#include "chrome/browser/extensions/extension_view_host.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/sidebar/sidebar_container.h"
#include "chrome/browser/sidebar/sidebar_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/extensions/accelerator_priority.h"
#include "chrome/browser/ui/extensions/extension_action_platform_delegate.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/extensions/api/extension_action/action_info.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_constants.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"

using extensions::ActionInfo;
using extensions::CommandService;

ExtensionActionViewController::ExtensionActionViewController(
    const extensions::Extension* extension,
    Browser* browser,
    ExtensionAction* extension_action)
    : extension_(extension),
      browser_(browser),
      extension_action_(extension_action),
      popup_host_(nullptr),
      view_delegate_(nullptr),
      platform_delegate_(ExtensionActionPlatformDelegate::Create(this)),
      icon_factory_(browser->profile(), extension, extension_action, this),
      icon_observer_(nullptr),
      extension_registry_(
          extensions::ExtensionRegistry::Get(browser_->profile())),
      popup_host_observer_(this) {
  DCHECK(extension_action);
  DCHECK(extension_action->action_type() == ActionInfo::TYPE_PAGE ||
         extension_action->action_type() == ActionInfo::TYPE_BROWSER);
  DCHECK(extension);
}

ExtensionActionViewController::~ExtensionActionViewController() {
  DCHECK(!is_showing_popup());

  SidebarManager::GetInstance()->RemoveObserver(this);
}

const std::string& ExtensionActionViewController::GetId() const {
  return extension_->id();
}

void ExtensionActionViewController::SetDelegate(
    ToolbarActionViewDelegate* delegate) {
  DCHECK((delegate == nullptr) ^ (view_delegate_ == nullptr));
  if (delegate) {
    view_delegate_ = delegate;
    platform_delegate_->OnDelegateSet();
  } else {
    if (is_showing_popup())
      HidePopup();
    platform_delegate_.reset();
    view_delegate_ = nullptr;
  }
}

gfx::Image ExtensionActionViewController::GetIcon(
    content::WebContents* web_contents) {
  if (!ExtensionIsValid())
    return gfx::Image();

  return icon_factory_.GetIcon(SessionTabHelper::IdForTab(web_contents));
}

gfx::ImageSkia ExtensionActionViewController::GetIconWithBadge() {
  if (!ExtensionIsValid())
    return gfx::ImageSkia();

  content::WebContents* web_contents = view_delegate_->GetCurrentWebContents();
  gfx::Size spacing(0, 3);
  gfx::ImageSkia icon = *GetIcon(web_contents).ToImageSkia();
  if (!IsEnabled(web_contents))
    icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25);
  return extension_action_->GetIconWithBadge(
      icon, SessionTabHelper::IdForTab(web_contents), spacing);
}

base::string16 ExtensionActionViewController::GetActionName() const {
  if (!ExtensionIsValid())
    return base::string16();

  return base::UTF8ToUTF16(extension_->name());
}

base::string16 ExtensionActionViewController::GetAccessibleName(
    content::WebContents* web_contents) const {
  if (!ExtensionIsValid())
    return base::string16();

  std::string title =
      extension_action()->GetTitle(SessionTabHelper::IdForTab(web_contents));
  return base::UTF8ToUTF16(title.empty() ? extension()->name() : title);
}

base::string16 ExtensionActionViewController::GetTooltip(
    content::WebContents* web_contents) const {
  return GetAccessibleName(web_contents);
}

bool ExtensionActionViewController::IsEnabled(
    content::WebContents* web_contents) const {
  if (!ExtensionIsValid())
    return false;

  return extension_action_->GetIsVisible(
      SessionTabHelper::IdForTab(web_contents)) ||
      extensions::ExtensionActionAPI::Get(browser_->profile())->
          ExtensionWantsToRun(extension(), web_contents);
}

bool ExtensionActionViewController::WantsToRun(
    content::WebContents* web_contents) const {
  return extensions::ExtensionActionAPI::Get(browser_->profile())->
      ExtensionWantsToRun(extension(), web_contents);
}

bool ExtensionActionViewController::HasPopup(
    content::WebContents* web_contents) const {
  if (!ExtensionIsValid())
    return false;

  int tab_id = SessionTabHelper::IdForTab(web_contents);
  return (tab_id < 0) ? false : extension_action_->HasPopup(tab_id);
}

void ExtensionActionViewController::HidePopup() {
  if (is_showing_popup()) {
    popup_host_->Close();
    // We need to do these actions synchronously (instead of closing and then
    // performing the rest of the cleanup in OnExtensionHostDestroyed()) because
    // the extension host can close asynchronously, and we need to keep the view
    // delegate up-to-date.
    OnPopupClosed();
  }
}

gfx::NativeView ExtensionActionViewController::GetPopupNativeView() {
  return popup_host_ ? popup_host_->view()->GetNativeView() : nullptr;
}

ui::MenuModel* ExtensionActionViewController::GetContextMenu() {
  if (!ExtensionIsValid() || !extension()->ShowConfigureContextMenus())
    return nullptr;

  // Reconstruct the menu every time because the menu's contents are dynamic.
  context_menu_model_ = make_scoped_refptr(new ExtensionContextMenuModel(
      extension(), browser_, this));
  return context_menu_model_.get();
}

bool ExtensionActionViewController::IsMenuRunning() const {
  return platform_delegate_->IsMenuRunning();
}

bool ExtensionActionViewController::CanDrag() const {
  return true;
}

bool ExtensionActionViewController::ExecuteAction(bool by_user) {
  return ExecuteAction(SHOW_POPUP, by_user);
}

void ExtensionActionViewController::UpdateState() {
  if (!ExtensionIsValid())
    return;

  view_delegate_->UpdateState();
}

bool ExtensionActionViewController::ExecuteAction(PopupShowAction show_action,
                                                  bool grant_tab_permissions) {
  if (!ExtensionIsValid())
    return false;

  if (extensions::ExtensionActionAPI::Get(browser_->profile())
          ->ExecuteExtensionAction(
              extension_, browser_, grant_tab_permissions) ==
      ExtensionAction::ACTION_SHOW_POPUP) {
    GURL popup_url = extension_action_->GetPopupUrl(
        SessionTabHelper::IdForTab(view_delegate_->GetCurrentWebContents()));
    return static_cast<ExtensionActionViewController*>(
               view_delegate_->GetPreferredPopupViewController())
        ->ShowPopupWithUrl(show_action, popup_url, grant_tab_permissions);
  }
  return false;
}

void ExtensionActionViewController::PaintExtra(
    gfx::Canvas* canvas,
    const gfx::Rect& bounds,
    content::WebContents* web_contents) const {
  if (!ExtensionIsValid())
    return;

  int tab_id = SessionTabHelper::IdForTab(web_contents);
  if (tab_id >= 0)
    extension_action_->PaintBadge(canvas, bounds, tab_id);
}

void ExtensionActionViewController::RegisterCommand() {
  if (!ExtensionIsValid())
    return;

  platform_delegate_->RegisterCommand();
}

void ExtensionActionViewController::InspectPopup() {
  ExecuteAction(SHOW_POPUP_AND_INSPECT, true);
}

void ExtensionActionViewController::OnIconUpdated() {
  if (icon_observer_)
    icon_observer_->OnIconUpdated();
  if (view_delegate_)
    view_delegate_->UpdateState();
}

void ExtensionActionViewController::OnExtensionHostDestroyed(
    const extensions::ExtensionHost* host) {
  OnPopupClosed();
}

bool ExtensionActionViewController::ExtensionIsValid() const {
  return extension_registry_->enabled_extensions().Contains(extension_->id());
}

bool ExtensionActionViewController::GetExtensionCommand(
    extensions::Command* command) {
  DCHECK(command);
  if (!ExtensionIsValid())
    return false;

  CommandService* command_service = CommandService::Get(browser_->profile());
  if (extension_action_->action_type() == ActionInfo::TYPE_PAGE) {
    return command_service->GetPageActionCommand(
        extension_->id(), CommandService::ACTIVE, command, NULL);
  }
  return command_service->GetBrowserActionCommand(
      extension_->id(), CommandService::ACTIVE, command, NULL);
}

bool ExtensionActionViewController::ShowPopupWithUrl(
    PopupShowAction show_action,
    const GURL& popup_url,
    bool grant_tab_permissions) {
  if (!ExtensionIsValid())
    return false;

  bool already_showing = is_showing_popup();

  // Always hide the current popup, even if it's not owned by this extension.
  // Only one popup should be visible at a time.
  platform_delegate_->CloseActivePopup();

  // If we were showing a popup already, then we treat the action to open the
  // same one as a desire to close it (like clicking a menu button that was
  // already open).
  if (already_showing)
    return false;

  bool use_sidebar =
      browser()->profile()->GetPrefs()->GetBoolean(prefs::kShowPopupInSidebar);

  if (use_sidebar) {
    SidebarManager* sidebar_manager = SidebarManager::GetInstance();
    content::WebContents* web_contents = view_delegate_->GetCurrentWebContents();

    if (active_in_webcontents_.find(web_contents) != active_in_webcontents_.end()) {
      sidebar_manager->HideSidebar(
          web_contents, GetId());
      return false;
    }

    active_in_webcontents_.insert(web_contents);
    sidebar_manager->AddObserver(this);
    sidebar_manager->ShowSidebar(
        web_contents, GetId());
    sidebar_manager->NavigateSidebar(
        web_contents, GetId(), popup_url);
    return true;
  }

  popup_host_ = platform_delegate_->ShowPopupWithUrl(
      show_action, popup_url, grant_tab_permissions);
  if (popup_host_) {
    popup_host_observer_.Add(popup_host_);
    view_delegate_->OnPopupShown(grant_tab_permissions);
  }

  return is_showing_popup();
}

void ExtensionActionViewController::OnPopupClosed() {
  popup_host_observer_.Remove(popup_host_);
  popup_host_ = nullptr;
  view_delegate_->OnPopupClosed();
}

void ExtensionActionViewController::OnSidebarShown(content::WebContents* tab,
                                                   const std::string& content_id) {
  if (view_delegate_->GetCurrentWebContents() == tab &&
    content_id == GetId())
    // Without the popup corner arrow indicator, marking the browserAction icon
    // is necessary for extension attribution
    view_delegate_->OnPopupShown(true);
}

void ExtensionActionViewController::OnSidebarHidden(content::WebContents* tab,
                                                    const std::string& content_id) {
  if (view_delegate_->GetCurrentWebContents() == tab &&
    content_id == GetId()) {
    view_delegate_->OnPopupClosed();
    active_in_webcontents_.erase(active_in_webcontents_.find(
                                     view_delegate_->GetCurrentWebContents()));
    if (active_in_webcontents_.size() == 0)
        SidebarManager::GetInstance()->RemoveObserver(this);
  }
}

void ExtensionActionViewController::OnSidebarSwitched(content::WebContents* old_tab,
                                                      const std::string& old_content_id,
                                                      content::WebContents* new_tab,
                                                      const std::string& new_content_id) {
    if (browser_->tab_strip_model()->GetIndexOfWebContents(new_tab ? new_tab : old_tab) == TabStripModel::kNoTab)
        return;

    if (view_delegate_->GetCurrentWebContents() == new_tab &&
        new_content_id == GetId())
        // Without the popup corner arrow indicator, marking the browserAction icon
        // is necessary for extension attribution
        view_delegate_->OnPopupShown(true);
    else
        view_delegate_->OnPopupClosed();
}
<commit_msg>Close all sidebars related with an extension when this one is removed<commit_after>// Copyright 2014 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/extensions/extension_action_view_controller.h"

#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/api/commands/command_service.h"
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_view.h"
#include "chrome/browser/extensions/extension_view_host.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/sidebar/sidebar_container.h"
#include "chrome/browser/sidebar/sidebar_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/extensions/accelerator_priority.h"
#include "chrome/browser/ui/extensions/extension_action_platform_delegate.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/extensions/api/extension_action/action_info.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_constants.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"

using extensions::ActionInfo;
using extensions::CommandService;

ExtensionActionViewController::ExtensionActionViewController(
    const extensions::Extension* extension,
    Browser* browser,
    ExtensionAction* extension_action)
    : extension_(extension),
      browser_(browser),
      extension_action_(extension_action),
      popup_host_(nullptr),
      view_delegate_(nullptr),
      platform_delegate_(ExtensionActionPlatformDelegate::Create(this)),
      icon_factory_(browser->profile(), extension, extension_action, this),
      icon_observer_(nullptr),
      extension_registry_(
          extensions::ExtensionRegistry::Get(browser_->profile())),
      popup_host_observer_(this) {
  DCHECK(extension_action);
  DCHECK(extension_action->action_type() == ActionInfo::TYPE_PAGE ||
         extension_action->action_type() == ActionInfo::TYPE_BROWSER);
  DCHECK(extension);
}

ExtensionActionViewController::~ExtensionActionViewController() {
  DCHECK(!is_showing_popup());

  SidebarManager *sidebar_manager = SidebarManager::GetInstance();
  sidebar_manager->RemoveObserver(this);
  for (std::set<content::WebContents*>::iterator it = active_in_webcontents_.begin();
       it != active_in_webcontents_.end();
       ++it)
      sidebar_manager->HideSidebar(*it, GetId());
}

const std::string& ExtensionActionViewController::GetId() const {
  return extension_->id();
}

void ExtensionActionViewController::SetDelegate(
    ToolbarActionViewDelegate* delegate) {
  DCHECK((delegate == nullptr) ^ (view_delegate_ == nullptr));
  if (delegate) {
    view_delegate_ = delegate;
    platform_delegate_->OnDelegateSet();
  } else {
    if (is_showing_popup())
      HidePopup();
    platform_delegate_.reset();
    view_delegate_ = nullptr;
  }
}

gfx::Image ExtensionActionViewController::GetIcon(
    content::WebContents* web_contents) {
  if (!ExtensionIsValid())
    return gfx::Image();

  return icon_factory_.GetIcon(SessionTabHelper::IdForTab(web_contents));
}

gfx::ImageSkia ExtensionActionViewController::GetIconWithBadge() {
  if (!ExtensionIsValid())
    return gfx::ImageSkia();

  content::WebContents* web_contents = view_delegate_->GetCurrentWebContents();
  gfx::Size spacing(0, 3);
  gfx::ImageSkia icon = *GetIcon(web_contents).ToImageSkia();
  if (!IsEnabled(web_contents))
    icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25);
  return extension_action_->GetIconWithBadge(
      icon, SessionTabHelper::IdForTab(web_contents), spacing);
}

base::string16 ExtensionActionViewController::GetActionName() const {
  if (!ExtensionIsValid())
    return base::string16();

  return base::UTF8ToUTF16(extension_->name());
}

base::string16 ExtensionActionViewController::GetAccessibleName(
    content::WebContents* web_contents) const {
  if (!ExtensionIsValid())
    return base::string16();

  std::string title =
      extension_action()->GetTitle(SessionTabHelper::IdForTab(web_contents));
  return base::UTF8ToUTF16(title.empty() ? extension()->name() : title);
}

base::string16 ExtensionActionViewController::GetTooltip(
    content::WebContents* web_contents) const {
  return GetAccessibleName(web_contents);
}

bool ExtensionActionViewController::IsEnabled(
    content::WebContents* web_contents) const {
  if (!ExtensionIsValid())
    return false;

  return extension_action_->GetIsVisible(
      SessionTabHelper::IdForTab(web_contents)) ||
      extensions::ExtensionActionAPI::Get(browser_->profile())->
          ExtensionWantsToRun(extension(), web_contents);
}

bool ExtensionActionViewController::WantsToRun(
    content::WebContents* web_contents) const {
  return extensions::ExtensionActionAPI::Get(browser_->profile())->
      ExtensionWantsToRun(extension(), web_contents);
}

bool ExtensionActionViewController::HasPopup(
    content::WebContents* web_contents) const {
  if (!ExtensionIsValid())
    return false;

  int tab_id = SessionTabHelper::IdForTab(web_contents);
  return (tab_id < 0) ? false : extension_action_->HasPopup(tab_id);
}

void ExtensionActionViewController::HidePopup() {
  if (is_showing_popup()) {
    popup_host_->Close();
    // We need to do these actions synchronously (instead of closing and then
    // performing the rest of the cleanup in OnExtensionHostDestroyed()) because
    // the extension host can close asynchronously, and we need to keep the view
    // delegate up-to-date.
    OnPopupClosed();
  }
}

gfx::NativeView ExtensionActionViewController::GetPopupNativeView() {
  return popup_host_ ? popup_host_->view()->GetNativeView() : nullptr;
}

ui::MenuModel* ExtensionActionViewController::GetContextMenu() {
  if (!ExtensionIsValid() || !extension()->ShowConfigureContextMenus())
    return nullptr;

  // Reconstruct the menu every time because the menu's contents are dynamic.
  context_menu_model_ = make_scoped_refptr(new ExtensionContextMenuModel(
      extension(), browser_, this));
  return context_menu_model_.get();
}

bool ExtensionActionViewController::IsMenuRunning() const {
  return platform_delegate_->IsMenuRunning();
}

bool ExtensionActionViewController::CanDrag() const {
  return true;
}

bool ExtensionActionViewController::ExecuteAction(bool by_user) {
  return ExecuteAction(SHOW_POPUP, by_user);
}

void ExtensionActionViewController::UpdateState() {
  if (!ExtensionIsValid())
    return;

  view_delegate_->UpdateState();
}

bool ExtensionActionViewController::ExecuteAction(PopupShowAction show_action,
                                                  bool grant_tab_permissions) {
  if (!ExtensionIsValid())
    return false;

  if (extensions::ExtensionActionAPI::Get(browser_->profile())
          ->ExecuteExtensionAction(
              extension_, browser_, grant_tab_permissions) ==
      ExtensionAction::ACTION_SHOW_POPUP) {
    GURL popup_url = extension_action_->GetPopupUrl(
        SessionTabHelper::IdForTab(view_delegate_->GetCurrentWebContents()));
    return static_cast<ExtensionActionViewController*>(
               view_delegate_->GetPreferredPopupViewController())
        ->ShowPopupWithUrl(show_action, popup_url, grant_tab_permissions);
  }
  return false;
}

void ExtensionActionViewController::PaintExtra(
    gfx::Canvas* canvas,
    const gfx::Rect& bounds,
    content::WebContents* web_contents) const {
  if (!ExtensionIsValid())
    return;

  int tab_id = SessionTabHelper::IdForTab(web_contents);
  if (tab_id >= 0)
    extension_action_->PaintBadge(canvas, bounds, tab_id);
}

void ExtensionActionViewController::RegisterCommand() {
  if (!ExtensionIsValid())
    return;

  platform_delegate_->RegisterCommand();
}

void ExtensionActionViewController::InspectPopup() {
  ExecuteAction(SHOW_POPUP_AND_INSPECT, true);
}

void ExtensionActionViewController::OnIconUpdated() {
  if (icon_observer_)
    icon_observer_->OnIconUpdated();
  if (view_delegate_)
    view_delegate_->UpdateState();
}

void ExtensionActionViewController::OnExtensionHostDestroyed(
    const extensions::ExtensionHost* host) {
  OnPopupClosed();
}

bool ExtensionActionViewController::ExtensionIsValid() const {
  return extension_registry_->enabled_extensions().Contains(extension_->id());
}

bool ExtensionActionViewController::GetExtensionCommand(
    extensions::Command* command) {
  DCHECK(command);
  if (!ExtensionIsValid())
    return false;

  CommandService* command_service = CommandService::Get(browser_->profile());
  if (extension_action_->action_type() == ActionInfo::TYPE_PAGE) {
    return command_service->GetPageActionCommand(
        extension_->id(), CommandService::ACTIVE, command, NULL);
  }
  return command_service->GetBrowserActionCommand(
      extension_->id(), CommandService::ACTIVE, command, NULL);
}

bool ExtensionActionViewController::ShowPopupWithUrl(
    PopupShowAction show_action,
    const GURL& popup_url,
    bool grant_tab_permissions) {
  if (!ExtensionIsValid())
    return false;

  bool already_showing = is_showing_popup();

  // Always hide the current popup, even if it's not owned by this extension.
  // Only one popup should be visible at a time.
  platform_delegate_->CloseActivePopup();

  // If we were showing a popup already, then we treat the action to open the
  // same one as a desire to close it (like clicking a menu button that was
  // already open).
  if (already_showing)
    return false;

  bool use_sidebar =
      browser()->profile()->GetPrefs()->GetBoolean(prefs::kShowPopupInSidebar);

  if (use_sidebar) {
    SidebarManager* sidebar_manager = SidebarManager::GetInstance();
    content::WebContents* web_contents = view_delegate_->GetCurrentWebContents();

    if (active_in_webcontents_.find(web_contents) != active_in_webcontents_.end()) {
      sidebar_manager->HideSidebar(
          web_contents, GetId());
      return false;
    }

    active_in_webcontents_.insert(web_contents);
    sidebar_manager->AddObserver(this);
    sidebar_manager->ShowSidebar(
        web_contents, GetId());
    sidebar_manager->NavigateSidebar(
        web_contents, GetId(), popup_url);
    return true;
  }

  popup_host_ = platform_delegate_->ShowPopupWithUrl(
      show_action, popup_url, grant_tab_permissions);
  if (popup_host_) {
    popup_host_observer_.Add(popup_host_);
    view_delegate_->OnPopupShown(grant_tab_permissions);
  }

  return is_showing_popup();
}

void ExtensionActionViewController::OnPopupClosed() {
  popup_host_observer_.Remove(popup_host_);
  popup_host_ = nullptr;
  view_delegate_->OnPopupClosed();
}

void ExtensionActionViewController::OnSidebarShown(content::WebContents* tab,
                                                   const std::string& content_id) {
  if (view_delegate_->GetCurrentWebContents() == tab &&
    content_id == GetId())
    // Without the popup corner arrow indicator, marking the browserAction icon
    // is necessary for extension attribution
    view_delegate_->OnPopupShown(true);
}

void ExtensionActionViewController::OnSidebarHidden(content::WebContents* tab,
                                                    const std::string& content_id) {
  if (view_delegate_->GetCurrentWebContents() == tab &&
    content_id == GetId()) {
    view_delegate_->OnPopupClosed();
    active_in_webcontents_.erase(active_in_webcontents_.find(
                                     view_delegate_->GetCurrentWebContents()));
    if (active_in_webcontents_.size() == 0)
        SidebarManager::GetInstance()->RemoveObserver(this);
  }
}

void ExtensionActionViewController::OnSidebarSwitched(content::WebContents* old_tab,
                                                      const std::string& old_content_id,
                                                      content::WebContents* new_tab,
                                                      const std::string& new_content_id) {
    if (browser_->tab_strip_model()->GetIndexOfWebContents(new_tab ? new_tab : old_tab) == TabStripModel::kNoTab)
        return;

    if (view_delegate_->GetCurrentWebContents() == new_tab &&
        new_content_id == GetId())
        // Without the popup corner arrow indicator, marking the browserAction icon
        // is necessary for extension attribution
        view_delegate_->OnPopupShown(true);
    else
        view_delegate_->OnPopupClosed();
}
<|endoftext|>


<commit_before>/*
 * (C) Copyright 2015 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE WebRtcEndpoint
#include <boost/test/unit_test.hpp>
#include <MediaPipelineImpl.hpp>
#include <objects/WebRtcEndpointImpl.hpp>
#include <IceCandidate.hpp>
#include <mutex>
#include <condition_variable>

using namespace kurento;

BOOST_AUTO_TEST_CASE (gathering_done)
{
  gst_init (NULL, NULL);

  std::atomic<bool> gathering_done (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  std::shared_ptr <MediaPipelineImpl> pipe (new MediaPipelineImpl (
        boost::property_tree::ptree() ) );
  boost::property_tree::ptree config;

  config.add ("configPath", "../../../tests" );
  config.add ("modules.kurento.SdpEndpoint.sdpPattern", "sdp_pattern.txt");
  config.add ("modules.kurento.SdpEndpoint.configPath", "../../../tests");

  std::shared_ptr <WebRtcEndpointImpl> webRtcEp ( new  WebRtcEndpointImpl
      (config, pipe) );

  webRtcEp->signalOnIceGatheringDone.connect ([&] (OnIceGatheringDone event) {
    gathering_done = true;
    cv.notify_one();
  });

  webRtcEp->generateOffer ();
  webRtcEp->gatherCandidates ();

  cv.wait_for (lck, std::chrono::seconds (5), [&] () {
    return gathering_done.load();
  });

  if (!gathering_done) {
    BOOST_ERROR ("Gathering not done");
  }

  webRtcEp.reset ();
}

BOOST_AUTO_TEST_CASE (ice_state_changes)
{
  gst_init (NULL, NULL);

  std::atomic<bool> ice_state_changed (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  std::shared_ptr <MediaPipelineImpl> pipe (new MediaPipelineImpl (
        boost::property_tree::ptree() ) );
  boost::property_tree::ptree config;

  config.add ("configPath", "../../../tests" );
  config.add ("modules.kurento.SdpEndpoint.sdpPattern", "sdp_pattern.txt");
  config.add ("modules.kurento.SdpEndpoint.configPath", "../../../tests");

  std::shared_ptr <WebRtcEndpointImpl> webRtcEpOfferer ( new  WebRtcEndpointImpl
      (config, pipe) );
  std::shared_ptr <WebRtcEndpointImpl> webRtcEpAnswerer ( new  WebRtcEndpointImpl
      (config, pipe) );

  webRtcEpOfferer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpAnswerer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpAnswerer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpOfferer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpOfferer->signalOnIceComponentStateChanged.connect ([&] (
  OnIceComponentStateChanged event) {
    ice_state_changed = true;
    cv.notify_one();
  });

  std::string offer = webRtcEpOfferer->generateOffer ();
  std::string answer = webRtcEpAnswerer->processOffer (offer);
  webRtcEpOfferer->processAnswer (answer);

  webRtcEpOfferer->gatherCandidates ();
  webRtcEpAnswerer->gatherCandidates ();

  cv.wait_for (lck, std::chrono::seconds (5), [&] () {
    return ice_state_changed.load();
  });

  if (!ice_state_changed) {
    BOOST_ERROR ("ICE state not chagned");
  }

  webRtcEpOfferer.reset ();
}

BOOST_AUTO_TEST_CASE (stun_turn_properties)
{
  gst_init (NULL, NULL);

  std::string stunServerAddress ("10.0.0.1");
  int stunServerPort = 2345;
  std::string turnUrl ("user0:pass0@10.0.0.2:3456");

  std::shared_ptr <MediaPipelineImpl> pipe (new MediaPipelineImpl (
        boost::property_tree::ptree() ) );
  boost::property_tree::ptree config;

  config.add ("configPath", "../../../tests" );
  config.add ("modules.kurento.SdpEndpoint.sdpPattern", "sdp_pattern.txt");
  config.add ("modules.kurento.SdpEndpoint.configPath", "../../../tests");

  std::shared_ptr <WebRtcEndpointImpl> webRtcEp ( new  WebRtcEndpointImpl
      (config, pipe) );

  webRtcEp->setStunServerAddress (stunServerAddress);
  std::string stunServerAddressRet = webRtcEp->getStunServerAddress ();
  BOOST_CHECK (stunServerAddressRet == stunServerAddress);

  webRtcEp->setStunServerPort (stunServerPort);
  int stunServerPortRet = webRtcEp->getStunServerPort ();
  BOOST_CHECK (stunServerPortRet == stunServerPort);

  webRtcEp->setTurnUrl (turnUrl);
  std::string turnUrlRet = webRtcEp->getTurnUrl ();
  BOOST_CHECK (turnUrlRet == turnUrl);
}
<commit_msg>webRtcEndpoint: Rework test to use factories instead of instantiating elements directly<commit_after>/*
 * (C) Copyright 2015 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE WebRtcEndpoint
#include <boost/test/unit_test.hpp>
#include <MediaPipelineImpl.hpp>
#include <objects/WebRtcEndpointImpl.hpp>
#include <IceCandidate.hpp>
#include <mutex>
#include <condition_variable>
#include <ModuleManager.hpp>
#include <KurentoException.hpp>
#include <MediaSet.hpp>

using namespace kurento;

boost::property_tree::ptree config;
std::string mediaPipelineId;
ModuleManager moduleManager;
std::once_flag init_flag;

static void
init_internal()
{
  gst_init (NULL, NULL);

  moduleManager.loadModulesFromDirectories ("../../src/server");

  config.add ("configPath", "../../../tests" );
  config.add ("modules.kurento.SdpEndpoint.sdpPattern", "sdp_pattern.txt");
  config.add ("modules.kurento.SdpEndpoint.configPath", "../../../tests");

  mediaPipelineId = moduleManager.getFactory ("MediaPipeline")->createObject (
                      config, "",
                      Json::Value() )->getId();
}

static void
init()
{
  std::call_once (init_flag, init_internal);
}

static std::shared_ptr <WebRtcEndpointImpl>
createWebrtc (void)
{
  std::shared_ptr <kurento::MediaObjectImpl> webrtcEndpoint;
  Json::Value constructorParams;

  constructorParams ["mediaPipeline"] = mediaPipelineId;

  webrtcEndpoint = moduleManager.getFactory ("WebRtcEndpoint")->createObject (
                     config, "",
                     constructorParams );

  return std::dynamic_pointer_cast <WebRtcEndpointImpl> (webrtcEndpoint);
}

static void
releaseWebRtc (std::shared_ptr<WebRtcEndpointImpl> &ep)
{
  std::string id = ep->getId();

  ep.reset();
  MediaSet::getMediaSet ()->release (id);
}

BOOST_AUTO_TEST_CASE (gathering_done)
{
  init ();

  std::atomic<bool> gathering_done (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);
  std::shared_ptr <WebRtcEndpointImpl> webRtcEp = createWebrtc();

  webRtcEp->signalOnIceGatheringDone.connect ([&] (OnIceGatheringDone event) {
    gathering_done = true;
    cv.notify_one();
  });

  webRtcEp->generateOffer ();
  webRtcEp->gatherCandidates ();

  cv.wait_for (lck, std::chrono::seconds (5), [&] () {
    return gathering_done.load();
  });

  if (!gathering_done) {
    BOOST_ERROR ("Gathering not done");
  }

  releaseWebRtc (webRtcEp);
}

BOOST_AUTO_TEST_CASE (ice_state_changes)
{
  init ();

  std::atomic<bool> ice_state_changed (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  std::shared_ptr <WebRtcEndpointImpl> webRtcEpOfferer = createWebrtc();
  std::shared_ptr <WebRtcEndpointImpl> webRtcEpAnswerer = createWebrtc();

  webRtcEpOfferer->setName ("offerer");
  webRtcEpAnswerer->setName ("answerer");

  webRtcEpOfferer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpAnswerer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpAnswerer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpOfferer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpOfferer->signalOnIceComponentStateChanged.connect ([&] (
  OnIceComponentStateChanged event) {
    ice_state_changed = true;
    cv.notify_one();
  });

  std::string offer = webRtcEpOfferer->generateOffer ();
  std::string answer = webRtcEpAnswerer->processOffer (offer);
  webRtcEpOfferer->processAnswer (answer);

  webRtcEpOfferer->gatherCandidates ();
  webRtcEpAnswerer->gatherCandidates ();

  cv.wait_for (lck, std::chrono::seconds (5), [&] () {
    return ice_state_changed.load();
  });

  if (!ice_state_changed) {
    BOOST_ERROR ("ICE state not chagned");
  }

  releaseWebRtc (webRtcEpOfferer);
  releaseWebRtc (webRtcEpAnswerer);
}

BOOST_AUTO_TEST_CASE (stun_turn_properties)
{
  std::string stunServerAddress ("10.0.0.1");
  int stunServerPort = 2345;
  std::string turnUrl ("user0:pass0@10.0.0.2:3456");

  init ();

  std::shared_ptr <WebRtcEndpointImpl> webRtcEp  = createWebrtc();

  webRtcEp->setStunServerAddress (stunServerAddress);
  std::string stunServerAddressRet = webRtcEp->getStunServerAddress ();
  BOOST_CHECK (stunServerAddressRet == stunServerAddress);

  webRtcEp->setStunServerPort (stunServerPort);
  int stunServerPortRet = webRtcEp->getStunServerPort ();
  BOOST_CHECK (stunServerPortRet == stunServerPort);

  webRtcEp->setTurnUrl (turnUrl);
  std::string turnUrlRet = webRtcEp->getTurnUrl ();
  BOOST_CHECK (turnUrlRet == turnUrl);

  releaseWebRtc (webRtcEp);
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/feature.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_helpers.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/vertex_converters.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/symbolizer.hpp>

// agg
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_color_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"
// for polygon_pattern_symbolizer
#include "agg_renderer_scanline.h"
#include "agg_span_allocator.h"
#include "agg_span_pattern_rgba.h"
#include "agg_image_accessors.h"
#include "agg_conv_clip_polygon.h"

namespace mapnik {

template <typename T0, typename T1>
void agg_renderer<T0,T1>::process(polygon_pattern_symbolizer const& sym,
                              mapnik::feature_impl & feature,
                              proj_transform const& prj_trans)
{
    std::string filename = get<std::string>(sym, keys::file, feature, common_.vars_);
    if (filename.empty()) return;
    boost::optional<mapnik::marker_ptr> marker = marker_cache::instance().find(filename, true);
    if (!marker) return;

    if (!(*marker)->is_bitmap())
    {
        MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer";
        return;
    }

    boost::optional<image_ptr> pat = (*marker)->get_bitmap_data();
    if (!pat) return;

    using clipped_geometry_type = agg::conv_clip_polygon<geometry_type>;
    using path_type = coord_transform<CoordTransform,clipped_geometry_type>;

    agg::rendering_buffer buf(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4);
    ras_ptr->reset();
    double gamma = get<value_double>(sym, keys::gamma, feature, common_.vars_, 1.0);
    gamma_method_enum gamma_method = get<gamma_method_enum>(sym, keys::gamma_method, feature, common_.vars_, GAMMA_POWER);
    if (gamma != gamma_ || gamma_method != gamma_method_)
    {
        set_gamma_method(ras_ptr, gamma, gamma_method);
        gamma_method_ = gamma_method;
        gamma_ = gamma;
    }

    bool clip = get<value_bool>(sym, keys::clip, feature, common_.vars_, false);
    double opacity = get<double>(sym,keys::stroke_opacity, feature, common_.vars_, 1.0);
    double simplify_tolerance = get<value_double>(sym, keys::simplify_tolerance, feature, common_.vars_, 0.0);
    double smooth = get<value_double>(sym, keys::smooth, feature, common_.vars_, false);

    box2d<double> clip_box = clipping_extent();

    using color = agg::rgba8;
    using order = agg::order_rgba;
    using blender_type = agg::comp_op_adaptor_rgba_pre<color, order>;
    using pixfmt_type = agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer>;

    using wrap_x_type = agg::wrap_mode_repeat;
    using wrap_y_type = agg::wrap_mode_repeat;
    using img_source_type = agg::image_accessor_wrap<agg::pixfmt_rgba32_pre,
                                                     wrap_x_type,
                                                     wrap_y_type>;

    using span_gen_type = agg::span_pattern_rgba<img_source_type>;
    using ren_base = agg::renderer_base<pixfmt_type>;

    using renderer_type = agg::renderer_scanline_aa_alpha<ren_base,
        agg::span_allocator<agg::rgba8>,
        span_gen_type>;

    pixfmt_type pixf(buf);
    pixf.comp_op(static_cast<agg::comp_op_e>(get<composite_mode_e>(sym, keys::comp_op, feature, common_.vars_, src_over)));
    ren_base renb(pixf);

    unsigned w=(*pat)->width();
    unsigned h=(*pat)->height();
    agg::rendering_buffer pattern_rbuf((agg::int8u*)(*pat)->getBytes(),w,h,w*4);
    agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf);
    img_source_type img_src(pixf_pattern);

    pattern_alignment_enum alignment = get<pattern_alignment_enum>(sym, keys::alignment, feature, common_.vars_, LOCAL_ALIGNMENT);
    unsigned offset_x=0;
    unsigned offset_y=0;

    if (alignment == LOCAL_ALIGNMENT)
    {
        double x0 = 0;
        double y0 = 0;
        if (feature.num_geometries() > 0)
        {
            clipped_geometry_type clipped(feature.get_geometry(0));
            clipped.clip_box(clip_box.minx(),clip_box.miny(),clip_box.maxx(),clip_box.maxy());
            path_type path(common_.t_,clipped,prj_trans);
            path.vertex(&x0,&y0);
        }
        offset_x = unsigned(current_buffer_->width() - x0);
        offset_y = unsigned(current_buffer_->height() - y0);
    }

    span_gen_type sg(img_src, offset_x, offset_y);

    agg::span_allocator<agg::rgba8> sa;
    renderer_type rp(renb,sa, sg, unsigned(opacity * 255));

    agg::trans_affine tr;
    auto transform = get_optional<transform_type>(sym, keys::geometry_transform);
    if (transform) evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_);

    using conv_types = boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag>;
    vertex_converter<box2d<double>, rasterizer, polygon_pattern_symbolizer,
                     CoordTransform, proj_transform, agg::trans_affine, conv_types, feature_impl>
        converter(clip_box,*ras_ptr,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_);

    if (prj_trans.equal() && clip) converter.set<clip_poly_tag>(); //optional clip (default: true)
    converter.set<transform_tag>(); //always transform
    converter.set<affine_transform_tag>(); // optional affine transform
    if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter
    if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter

    for ( geometry_type & geom : feature.paths())
    {
        if (geom.size() > 2)
        {
            converter.apply(geom);
        }
    }
    agg::scanline_u8 sl;
    ras_ptr->filling_rule(agg::fill_even_odd);
    agg::render_scanlines(*ras_ptr, sl, rp);
}

template void agg_renderer<image_32>::process(polygon_pattern_symbolizer const&,
                                              mapnik::feature_impl &,
                                              proj_transform const&);

}
<commit_msg>polygon_pattern_symbolizer - fix 'opacity'<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/feature.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_helpers.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/vertex_converters.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/symbolizer.hpp>

// agg
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_color_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"
// for polygon_pattern_symbolizer
#include "agg_renderer_scanline.h"
#include "agg_span_allocator.h"
#include "agg_span_pattern_rgba.h"
#include "agg_image_accessors.h"
#include "agg_conv_clip_polygon.h"

namespace mapnik {

template <typename T0, typename T1>
void agg_renderer<T0,T1>::process(polygon_pattern_symbolizer const& sym,
                              mapnik::feature_impl & feature,
                              proj_transform const& prj_trans)
{
    std::string filename = get<std::string>(sym, keys::file, feature, common_.vars_);
    if (filename.empty()) return;
    boost::optional<mapnik::marker_ptr> marker = marker_cache::instance().find(filename, true);
    if (!marker) return;

    boost::optional<image_ptr> pat;

    if (!(*marker)->is_bitmap())
    {
        MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer";
        return;
    }

    pat = (*marker)->get_bitmap_data();

    if (!pat) return;

    using clipped_geometry_type = agg::conv_clip_polygon<geometry_type>;
    using path_type = coord_transform<CoordTransform,clipped_geometry_type>;

    agg::rendering_buffer buf(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4);
    ras_ptr->reset();
    double gamma = get<value_double>(sym, keys::gamma, feature, common_.vars_, 1.0);
    gamma_method_enum gamma_method = get<gamma_method_enum>(sym, keys::gamma_method, feature, common_.vars_, GAMMA_POWER);
    if (gamma != gamma_ || gamma_method != gamma_method_)
    {
        set_gamma_method(ras_ptr, gamma, gamma_method);
        gamma_method_ = gamma_method;
        gamma_ = gamma;
    }

    bool clip = get<value_bool>(sym, keys::clip, feature, common_.vars_, false);
    double opacity = get<double>(sym,keys::opacity, feature, common_.vars_, 1.0);
    double simplify_tolerance = get<value_double>(sym, keys::simplify_tolerance, feature, common_.vars_, 0.0);
    double smooth = get<value_double>(sym, keys::smooth, feature, common_.vars_, false);

    box2d<double> clip_box = clipping_extent();

    using color = agg::rgba8;
    using order = agg::order_rgba;
    using blender_type = agg::comp_op_adaptor_rgba_pre<color, order>;
    using pixfmt_type = agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer>;

    using wrap_x_type = agg::wrap_mode_repeat;
    using wrap_y_type = agg::wrap_mode_repeat;
    using img_source_type = agg::image_accessor_wrap<agg::pixfmt_rgba32_pre,
                                                     wrap_x_type,
                                                     wrap_y_type>;

    using span_gen_type = agg::span_pattern_rgba<img_source_type>;
    using ren_base = agg::renderer_base<pixfmt_type>;

    using renderer_type = agg::renderer_scanline_aa_alpha<ren_base,
        agg::span_allocator<agg::rgba8>,
        span_gen_type>;

    pixfmt_type pixf(buf);
    pixf.comp_op(static_cast<agg::comp_op_e>(get<composite_mode_e>(sym, keys::comp_op, feature, common_.vars_, src_over)));
    ren_base renb(pixf);

    unsigned w=(*pat)->width();
    unsigned h=(*pat)->height();
    agg::rendering_buffer pattern_rbuf((agg::int8u*)(*pat)->getBytes(),w,h,w*4);
    agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf);
    img_source_type img_src(pixf_pattern);

    pattern_alignment_enum alignment = get<pattern_alignment_enum>(sym, keys::alignment, feature, common_.vars_, LOCAL_ALIGNMENT);
    unsigned offset_x=0;
    unsigned offset_y=0;

    if (alignment == LOCAL_ALIGNMENT)
    {
        double x0 = 0;
        double y0 = 0;
        if (feature.num_geometries() > 0)
        {
            clipped_geometry_type clipped(feature.get_geometry(0));
            clipped.clip_box(clip_box.minx(),clip_box.miny(),clip_box.maxx(),clip_box.maxy());
            path_type path(common_.t_,clipped,prj_trans);
            path.vertex(&x0,&y0);
        }
        offset_x = unsigned(current_buffer_->width() - x0);
        offset_y = unsigned(current_buffer_->height() - y0);
    }

    span_gen_type sg(img_src, offset_x, offset_y);

    agg::span_allocator<agg::rgba8> sa;
    renderer_type rp(renb,sa, sg, unsigned(opacity * 255));

    agg::trans_affine tr;
    auto transform = get_optional<transform_type>(sym, keys::geometry_transform);
    if (transform) evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_);

    using conv_types = boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag>;
    vertex_converter<box2d<double>, rasterizer, polygon_pattern_symbolizer,
                     CoordTransform, proj_transform, agg::trans_affine, conv_types, feature_impl>
        converter(clip_box,*ras_ptr,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_);

    if (prj_trans.equal() && clip) converter.set<clip_poly_tag>(); //optional clip (default: true)
    converter.set<transform_tag>(); //always transform
    converter.set<affine_transform_tag>(); // optional affine transform
    if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter
    if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter

    for ( geometry_type & geom : feature.paths())
    {
        if (geom.size() > 2)
        {
            converter.apply(geom);
        }
    }
    agg::scanline_u8 sl;
    ras_ptr->filling_rule(agg::fill_even_odd);
    agg::render_scanlines(*ras_ptr, sl, rp);
}

template void agg_renderer<image_32>::process(polygon_pattern_symbolizer const&,
                                              mapnik::feature_impl &,
                                              proj_transform const&);

}
<|endoftext|>


<commit_before>//..............................................................................
//
//  This file is part of the AXL library.
//
//  AXL is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/axl/license.txt
//
//..............................................................................

#include "pch.h"
#include "axl_io_Serial.h"
#include "axl_sys_win_DeviceInfo.h"

#define _AXL_ENUMERATE_DEVICE_CLASS 1

#include <initguid.h>
#include <devguid.h>

namespace axl {
namespace io {

//..............................................................................

class SerialPortEnumerator {
public:
	static
	size_t
	createPortList(
		sl::List<SerialPortDesc>* portList,
		uint_t mask
	);

protected:
	static
	SerialPortDesc*
	createPortDesc(
		sys::win::DeviceInfo* deviceInfo,
		uint_t mask
	);
};

//..............................................................................

size_t
SerialPortEnumerator::createPortList(
	sl::List<SerialPortDesc>* portList,
	uint_t mask
) {
	bool result;

	portList->clear();

	sys::win::DeviceInfoSet deviceInfoSet;

#ifdef _AXL_ENUMERATE_DEVICE_CLASS
	result = deviceInfoSet.create(GUID_DEVCLASS_PORTS, DIGCF_PRESENT);
#else
	result = deviceInfoSet.create(GUID_DEVINTERFACE_COMPORT, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
#endif

	if (!result)
		return 0;

	for (size_t i = 0;; i++) {
		sys::win::DeviceInfo deviceInfo;
		result = deviceInfoSet.getDeviceInfo(i, &deviceInfo);
		if (!result)
			break;

		SerialPortDesc* portDesc = createPortDesc(&deviceInfo, mask);
		if (portDesc)
			portList->insertTail(portDesc);
	}

	return portList->getCount();
}

sl::String
readRegistryStringValue(
	HKEY hKey,
	const wchar_t* valueName
) {
	dword_t type = 0;
	dword_t size = 0;

	long result = ::RegQueryValueExW(hKey, valueName, NULL, &type, NULL, &size);
	if (result != ERROR_SUCCESS)
		return sl::String();

	wchar_t buffer[256];
	sl::Array<byte_t> valueBuffer(rc::BufKind_Stack, buffer, sizeof(buffer));
	valueBuffer.setCount(size);

	result = ::RegQueryValueExW(
		hKey,
		valueName,
		NULL,
		&type,
		valueBuffer,
		&size
	);

	return result == ERROR_SUCCESS && size > sizeof(wchar_t) ?
		sl::String((wchar_t*)valueBuffer.cp(), size / sizeof(wchar_t) - 1) :
		sl::String();
}

SerialPortDesc*
SerialPortEnumerator::createPortDesc(
	sys::win::DeviceInfo* deviceInfo,
	uint_t mask
) {
	sys::win::RegKeyHandle devRegKey = deviceInfo->openDeviceRegistryKey(KEY_QUERY_VALUE);
	if (devRegKey == INVALID_HANDLE_VALUE)
		return NULL;

	SerialPortDesc* portDesc = AXL_MEM_NEW(SerialPortDesc);
	portDesc->m_deviceName = readRegistryStringValue(devRegKey, L"PortName");

	if (mask & SerialPortDescMask_Description) {
		deviceInfo->getDeviceRegistryProperty(SPDRP_FRIENDLYNAME, &portDesc->m_description);

		if (portDesc->m_description.isEmpty()) // try another property
			deviceInfo->getDeviceRegistryProperty(SPDRP_DEVICEDESC, &portDesc->m_description);
	}

	if (mask & SerialPortDescMask_Manufacturer)
		deviceInfo->getDeviceRegistryProperty(SPDRP_MFG, &portDesc->m_manufacturer);

	if (mask & SerialPortDescMask_HardwareIds)
		deviceInfo->getDeviceRegistryProperty(SPDRP_HARDWAREID, &portDesc->m_hardwareIds);

	if (mask & SerialPortDescMask_Driver) {
		deviceInfo->getDeviceRegistryProperty(SPDRP_SERVICE, &portDesc->m_driver);

		if (!portDesc->m_driver.isEmpty()) {
			sl::String_w regPath = L"System\\CurrentControlSet\\Services\\";
			regPath += portDesc->m_driver;

			sys::win::RegKeyHandle serviceRegKey;
			long result = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, regPath, 0, KEY_QUERY_VALUE, serviceRegKey.p());
			if (result == ERROR_SUCCESS) {
				sl::String driverPath = readRegistryStringValue(serviceRegKey, L"ImagePath");
				if (!driverPath.isEmpty())
					portDesc->m_driver.appendFormat(" (%s)", driverPath.sz());
			}
		}
	}

	if (mask & SerialPortDescMask_Location)
		deviceInfo->getDeviceRegistryProperty(SPDRP_LOCATION_PATHS, &portDesc->m_location);

#if (0)
	struct DeviceProp {
		const char* m_name;
		uint_t m_id;
	};

	static DeviceProp propTable[] = {
		{ "SPDRP_DEVICEDESC",                   SPDRP_DEVICEDESC                  }, // (0x00000000)  // DeviceDesc (R/W)
		{ "SPDRP_HARDWAREID",                   SPDRP_HARDWAREID                  }, // (0x00000001)  // HardwareID (R/W)
		{ "SPDRP_COMPATIBLEIDS",                SPDRP_COMPATIBLEIDS               }, // (0x00000002)  // CompatibleIDs (R/W)
		{ "SPDRP_SERVICE",                      SPDRP_SERVICE                     }, // (0x00000004)  // Service (R/W)
		{ "SPDRP_CLASS",                        SPDRP_CLASS                       }, // (0x00000007)  // Class (R--tied to ClassGUID)
		{ "SPDRP_CLASSGUID",                    SPDRP_CLASSGUID                   }, // (0x00000008)  // ClassGUID (R/W)
		{ "SPDRP_DRIVER",                       SPDRP_DRIVER                      }, // (0x00000009)  // Driver (R/W)
		{ "SPDRP_CONFIGFLAGS",                  SPDRP_CONFIGFLAGS                 }, // (0x0000000A)  // ConfigFlags (R/W)
		{ "SPDRP_MFG",                          SPDRP_MFG                         }, // (0x0000000B)  // Mfg (R/W)
		{ "SPDRP_FRIENDLYNAME",                 SPDRP_FRIENDLYNAME                }, // (0x0000000C)  // FriendlyName (R/W)
		{ "SPDRP_LOCATION_INFORMATION",         SPDRP_LOCATION_INFORMATION        }, // (0x0000000D)  // LocationInformation (R/W)
		{ "SPDRP_PHYSICAL_DEVICE_OBJECT_NAME",  SPDRP_PHYSICAL_DEVICE_OBJECT_NAME }, // (0x0000000E)  // PhysicalDeviceObjectName (R)
		{ "SPDRP_CAPABILITIES",                 SPDRP_CAPABILITIES                }, // (0x0000000F)  // Capabilities (R)
		{ "SPDRP_UI_NUMBER",                    SPDRP_UI_NUMBER                   }, // (0x00000010)  // UiNumber (R)
		{ "SPDRP_UPPERFILTERS",                 SPDRP_UPPERFILTERS                }, // (0x00000011)  // UpperFilters (R/W)
		{ "SPDRP_LOWERFILTERS",                 SPDRP_LOWERFILTERS                }, // (0x00000012)  // LowerFilters (R/W)
		{ "SPDRP_BUSTYPEGUID",                  SPDRP_BUSTYPEGUID                 }, // (0x00000013)  // BusTypeGUID (R)
		{ "SPDRP_LEGACYBUSTYPE",                SPDRP_LEGACYBUSTYPE               }, // (0x00000014)  // LegacyBusType (R)
		{ "SPDRP_BUSNUMBER",                    SPDRP_BUSNUMBER                   }, // (0x00000015)  // BusNumber (R)
		{ "SPDRP_ENUMERATOR_NAME",              SPDRP_ENUMERATOR_NAME             }, // (0x00000016)  // Enumerator Name (R)
		{ "SPDRP_SECURITY",                     SPDRP_SECURITY                    }, // (0x00000017)  // Security (R/W, binary form)
		{ "SPDRP_SECURITY_SDS",                 SPDRP_SECURITY_SDS                }, // (0x00000018)  // Security (W, SDS form)
		{ "SPDRP_DEVTYPE",                      SPDRP_DEVTYPE                     }, // (0x00000019)  // Device Type (R/W)
		{ "SPDRP_EXCLUSIVE",                    SPDRP_EXCLUSIVE                   }, // (0x0000001A)  // Device is exclusive-access (R/W)
		{ "SPDRP_CHARACTERISTICS",              SPDRP_CHARACTERISTICS             }, // (0x0000001B)  // Device Characteristics (R/W)
		{ "SPDRP_ADDRESS",                      SPDRP_ADDRESS                     }, // (0x0000001C)  // Device Address (R)
		{ "SPDRP_UI_NUMBER_DESC_FORMAT",        SPDRP_UI_NUMBER_DESC_FORMAT       }, // (0X0000001D)  // UiNumberDescFormat (R/W)
		{ "SPDRP_DEVICE_POWER_DATA",            SPDRP_DEVICE_POWER_DATA           }, // (0x0000001E)  // Device Power Data (R)
		{ "SPDRP_REMOVAL_POLICY",               SPDRP_REMOVAL_POLICY              }, // (0x0000001F)  // Removal Policy (R)
		{ "SPDRP_REMOVAL_POLICY_HW_DEFAULT",    SPDRP_REMOVAL_POLICY_HW_DEFAULT   }, // (0x00000020)  // Hardware Removal Policy (R)
		{ "SPDRP_REMOVAL_POLICY_OVERRIDE",      SPDRP_REMOVAL_POLICY_OVERRIDE     }, // (0x00000021)  // Removal Policy Override (RW)
		{ "SPDRP_INSTALL_STATE",                SPDRP_INSTALL_STATE               }, // (0x00000022)  // Device Install State (R)
		{ "SPDRP_LOCATION_PATHS",               SPDRP_LOCATION_PATHS              }, // (0x00000023)  // Device Location Paths (R)
		{ "SPDRP_BASE_CONTAINERID",             SPDRP_BASE_CONTAINERID            }, // (0x00000024)  // Base ContainerID (R)
	};

	for (size_t i = 0; i < countof(propTable); i++) {
		sl::String value;
		deviceInfo->getDeviceRegistryProperty(propTable[i].m_id, &value);
		printf("%s: %s\n", propTable[i].m_name, value.sz());
	}
#endif

	return portDesc;
}

//..............................................................................

size_t
createSerialPortDescList(
	sl::List<SerialPortDesc>* portList,
	uint_t mask
) {
	return SerialPortEnumerator::createPortList(portList, mask);
}

//..............................................................................

} // namespace io
} // namespace axl
<commit_msg>[axl_io_win] replace service name with image path in SerialPortDesc.m_driver<commit_after>//..............................................................................
//
//  This file is part of the AXL library.
//
//  AXL is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/axl/license.txt
//
//..............................................................................

#include "pch.h"
#include "axl_io_Serial.h"
#include "axl_sys_win_DeviceInfo.h"

#define _AXL_ENUMERATE_DEVICE_CLASS 1

#include <initguid.h>
#include <devguid.h>

namespace axl {
namespace io {

//..............................................................................

class SerialPortEnumerator {
public:
	static
	size_t
	createPortList(
		sl::List<SerialPortDesc>* portList,
		uint_t mask
	);

protected:
	static
	SerialPortDesc*
	createPortDesc(
		sys::win::DeviceInfo* deviceInfo,
		uint_t mask
	);
};

//..............................................................................

size_t
SerialPortEnumerator::createPortList(
	sl::List<SerialPortDesc>* portList,
	uint_t mask
) {
	bool result;

	portList->clear();

	sys::win::DeviceInfoSet deviceInfoSet;

#ifdef _AXL_ENUMERATE_DEVICE_CLASS
	result = deviceInfoSet.create(GUID_DEVCLASS_PORTS, DIGCF_PRESENT);
#else
	result = deviceInfoSet.create(GUID_DEVINTERFACE_COMPORT, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
#endif

	if (!result)
		return 0;

	for (size_t i = 0;; i++) {
		sys::win::DeviceInfo deviceInfo;
		result = deviceInfoSet.getDeviceInfo(i, &deviceInfo);
		if (!result)
			break;

		SerialPortDesc* portDesc = createPortDesc(&deviceInfo, mask);
		if (portDesc)
			portList->insertTail(portDesc);
	}

	return portList->getCount();
}

sl::String
readRegistryStringValue(
	HKEY hKey,
	const wchar_t* valueName
) {
	dword_t type = 0;
	dword_t size = 0;

	long result = ::RegQueryValueExW(hKey, valueName, NULL, &type, NULL, &size);
	if (result != ERROR_SUCCESS)
		return sl::String();

	wchar_t buffer[256];
	sl::Array<byte_t> valueBuffer(rc::BufKind_Stack, buffer, sizeof(buffer));
	valueBuffer.setCount(size);

	result = ::RegQueryValueExW(
		hKey,
		valueName,
		NULL,
		&type,
		valueBuffer,
		&size
	);

	return result == ERROR_SUCCESS && size > sizeof(wchar_t) ?
		sl::String((wchar_t*)valueBuffer.cp(), size / sizeof(wchar_t) - 1) :
		sl::String();
}

SerialPortDesc*
SerialPortEnumerator::createPortDesc(
	sys::win::DeviceInfo* deviceInfo,
	uint_t mask
) {
	sys::win::RegKeyHandle devRegKey = deviceInfo->openDeviceRegistryKey(KEY_QUERY_VALUE);
	if (devRegKey == INVALID_HANDLE_VALUE)
		return NULL;

	SerialPortDesc* portDesc = AXL_MEM_NEW(SerialPortDesc);
	portDesc->m_deviceName = readRegistryStringValue(devRegKey, L"PortName");

	if (mask & SerialPortDescMask_Description) {
		deviceInfo->getDeviceRegistryProperty(SPDRP_FRIENDLYNAME, &portDesc->m_description);

		if (portDesc->m_description.isEmpty()) // try another property
			deviceInfo->getDeviceRegistryProperty(SPDRP_DEVICEDESC, &portDesc->m_description);
	}

	if (mask & SerialPortDescMask_Manufacturer)
		deviceInfo->getDeviceRegistryProperty(SPDRP_MFG, &portDesc->m_manufacturer);

	if (mask & SerialPortDescMask_HardwareIds)
		deviceInfo->getDeviceRegistryProperty(SPDRP_HARDWAREID, &portDesc->m_hardwareIds);

	if (mask & SerialPortDescMask_Driver) {
		deviceInfo->getDeviceRegistryProperty(SPDRP_SERVICE, &portDesc->m_driver);

		if (!portDesc->m_driver.isEmpty()) {
			sl::String_w regPath = L"System\\CurrentControlSet\\Services\\";
			regPath += portDesc->m_driver;

			sys::win::RegKeyHandle serviceRegKey;
			long result = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, regPath, 0, KEY_QUERY_VALUE, serviceRegKey.p());
			if (result == ERROR_SUCCESS) {
				sl::String driverPath = readRegistryStringValue(serviceRegKey, L"ImagePath");
				if (!driverPath.isEmpty())
					portDesc->m_driver = driverPath;
			}
		}
	}

	if (mask & SerialPortDescMask_Location)
		deviceInfo->getDeviceRegistryProperty(SPDRP_LOCATION_PATHS, &portDesc->m_location);

#if (0)
	struct DeviceProp {
		const char* m_name;
		uint_t m_id;
	};

	static DeviceProp propTable[] = {
		{ "SPDRP_DEVICEDESC",                   SPDRP_DEVICEDESC                  }, // (0x00000000)  // DeviceDesc (R/W)
		{ "SPDRP_HARDWAREID",                   SPDRP_HARDWAREID                  }, // (0x00000001)  // HardwareID (R/W)
		{ "SPDRP_COMPATIBLEIDS",                SPDRP_COMPATIBLEIDS               }, // (0x00000002)  // CompatibleIDs (R/W)
		{ "SPDRP_SERVICE",                      SPDRP_SERVICE                     }, // (0x00000004)  // Service (R/W)
		{ "SPDRP_CLASS",                        SPDRP_CLASS                       }, // (0x00000007)  // Class (R--tied to ClassGUID)
		{ "SPDRP_CLASSGUID",                    SPDRP_CLASSGUID                   }, // (0x00000008)  // ClassGUID (R/W)
		{ "SPDRP_DRIVER",                       SPDRP_DRIVER                      }, // (0x00000009)  // Driver (R/W)
		{ "SPDRP_CONFIGFLAGS",                  SPDRP_CONFIGFLAGS                 }, // (0x0000000A)  // ConfigFlags (R/W)
		{ "SPDRP_MFG",                          SPDRP_MFG                         }, // (0x0000000B)  // Mfg (R/W)
		{ "SPDRP_FRIENDLYNAME",                 SPDRP_FRIENDLYNAME                }, // (0x0000000C)  // FriendlyName (R/W)
		{ "SPDRP_LOCATION_INFORMATION",         SPDRP_LOCATION_INFORMATION        }, // (0x0000000D)  // LocationInformation (R/W)
		{ "SPDRP_PHYSICAL_DEVICE_OBJECT_NAME",  SPDRP_PHYSICAL_DEVICE_OBJECT_NAME }, // (0x0000000E)  // PhysicalDeviceObjectName (R)
		{ "SPDRP_CAPABILITIES",                 SPDRP_CAPABILITIES                }, // (0x0000000F)  // Capabilities (R)
		{ "SPDRP_UI_NUMBER",                    SPDRP_UI_NUMBER                   }, // (0x00000010)  // UiNumber (R)
		{ "SPDRP_UPPERFILTERS",                 SPDRP_UPPERFILTERS                }, // (0x00000011)  // UpperFilters (R/W)
		{ "SPDRP_LOWERFILTERS",                 SPDRP_LOWERFILTERS                }, // (0x00000012)  // LowerFilters (R/W)
		{ "SPDRP_BUSTYPEGUID",                  SPDRP_BUSTYPEGUID                 }, // (0x00000013)  // BusTypeGUID (R)
		{ "SPDRP_LEGACYBUSTYPE",                SPDRP_LEGACYBUSTYPE               }, // (0x00000014)  // LegacyBusType (R)
		{ "SPDRP_BUSNUMBER",                    SPDRP_BUSNUMBER                   }, // (0x00000015)  // BusNumber (R)
		{ "SPDRP_ENUMERATOR_NAME",              SPDRP_ENUMERATOR_NAME             }, // (0x00000016)  // Enumerator Name (R)
		{ "SPDRP_SECURITY",                     SPDRP_SECURITY                    }, // (0x00000017)  // Security (R/W, binary form)
		{ "SPDRP_SECURITY_SDS",                 SPDRP_SECURITY_SDS                }, // (0x00000018)  // Security (W, SDS form)
		{ "SPDRP_DEVTYPE",                      SPDRP_DEVTYPE                     }, // (0x00000019)  // Device Type (R/W)
		{ "SPDRP_EXCLUSIVE",                    SPDRP_EXCLUSIVE                   }, // (0x0000001A)  // Device is exclusive-access (R/W)
		{ "SPDRP_CHARACTERISTICS",              SPDRP_CHARACTERISTICS             }, // (0x0000001B)  // Device Characteristics (R/W)
		{ "SPDRP_ADDRESS",                      SPDRP_ADDRESS                     }, // (0x0000001C)  // Device Address (R)
		{ "SPDRP_UI_NUMBER_DESC_FORMAT",        SPDRP_UI_NUMBER_DESC_FORMAT       }, // (0X0000001D)  // UiNumberDescFormat (R/W)
		{ "SPDRP_DEVICE_POWER_DATA",            SPDRP_DEVICE_POWER_DATA           }, // (0x0000001E)  // Device Power Data (R)
		{ "SPDRP_REMOVAL_POLICY",               SPDRP_REMOVAL_POLICY              }, // (0x0000001F)  // Removal Policy (R)
		{ "SPDRP_REMOVAL_POLICY_HW_DEFAULT",    SPDRP_REMOVAL_POLICY_HW_DEFAULT   }, // (0x00000020)  // Hardware Removal Policy (R)
		{ "SPDRP_REMOVAL_POLICY_OVERRIDE",      SPDRP_REMOVAL_POLICY_OVERRIDE     }, // (0x00000021)  // Removal Policy Override (RW)
		{ "SPDRP_INSTALL_STATE",                SPDRP_INSTALL_STATE               }, // (0x00000022)  // Device Install State (R)
		{ "SPDRP_LOCATION_PATHS",               SPDRP_LOCATION_PATHS              }, // (0x00000023)  // Device Location Paths (R)
		{ "SPDRP_BASE_CONTAINERID",             SPDRP_BASE_CONTAINERID            }, // (0x00000024)  // Base ContainerID (R)
	};

	for (size_t i = 0; i < countof(propTable); i++) {
		sl::String value;
		deviceInfo->getDeviceRegistryProperty(propTable[i].m_id, &value);
		printf("%s: %s\n", propTable[i].m_name, value.sz());
	}
#endif

	return portDesc;
}

//..............................................................................

size_t
createSerialPortDescList(
	sl::List<SerialPortDesc>* portList,
	uint_t mask
) {
	return SerialPortEnumerator::createPortList(portList, mask);
}

//..............................................................................

} // namespace io
} // namespace axl
<|endoftext|>