<commit_before>/*! \file urbi/usyncclient.hh
****************************************************************************
 *
 * Definition of the URBI interface class
 *
 * Copyright (C) 2004, 2006, 2007, 2008, 2009 Jean-Christophe Baillie.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
**********************************************************************/

#ifndef URBI_USYNCCLIENT_HH
# define URBI_USYNCCLIENT_HH

# include <libport/finally.hh>
# include <libport/fwd.hh>
# include <libport/lockable.hh>
# include <libport/semaphore.hh>
# include <libport/utime.hh>
# include <libport/pthread.h>

# include <urbi/uclient.hh>

namespace urbi
{
  /*! Format in which image requested with syncGetSound are transmitted*/
  enum UTransmitFormat
  {
    /// Transmit images compressed in JPEG.
    URBI_TRANSMIT_JPEG,
    /// Transmit raw YCbCr images.
    URBI_TRANSMIT_YCbCr
  };

  /// UClient linux implementation with support for synchronous extra
  /// functions.
  /*! This class provides extra functions to synchronously request
     values. These functions can safely be called frow within a
     callback function.

     All callbacks will be called in a separate thread created in the
     constructor.
     When one of those callbacks calls a synchronous function, new incoming
     messages are kept on hold until the response from the synchronous call
     is received.

     If you want to call these callbacks in a different
     thread, call @stopCallbackThread, then regularly call
     @processEvents. Each call will call callbacks for all pending
     messages in the current thread.  */
  class URBI_SDK_API USyncClient: public UClient
  {
  public:
    typedef boost::function1<void, USyncClient*> connect_callback_type;
    typedef UClient super_type;
    typedef super_type::error_type error_type;

    /// Option structure for USyncClient construction.
    ///
    /// In addition to UClient::options, provides:
    /// - startCallbackThread
    /// - connectCallback.
    struct URBI_SDK_API options
      : public super_type::options
    {
      options();
      /// If true, create a thread dedicated to the processing of
      /// incoming messages. If false, it is the responsibility of the
      /// user to regularly call processEvents().  Defaults to true.
      UCLIENT_OPTION(bool, startCallbackThread);
      /// Ignore host and port if set, do not connect or listen.
      /// Called when connection is established.
      UCLIENT_OPTION(connect_callback_type, connectCallback);
    };

    /** Create a new connection to an Urbi Server. Blocks until the connexion
     * is established.
     *
     *  \param host    The host to connect to.
     *  \param port    the port number to connect to, defaults to URBI_PORT.
     *  \param buflen  Size of reception buffer, defaults to URBI_BUFLEN.
     *  \param opt     Parameters of this USyncClient.
     */
    USyncClient(const std::string& host,
		unsigned port = URBI_PORT,
		size_t buflen = URBI_BUFLEN,
                const options& opt = options());

    ~USyncClient();

    /// Options for send(), rather than multiplying the overloads.
    struct send_options
    {
      send_options();

      send_options& timeout(libport::utime_t);
      send_options& tag(const char*, const char* = 0);

      /// Timeout in microseconds
      libport::utime_t timeout_;
      const char* mtag_;
      const char* mmod_;
      static const send_options default_options;
    };

  protected:
    virtual error_type onClose ();

  protected:
    /** Synchronously ask the server for the value of an expression.
     * \param expression   the Urbi expression to evaluate.
     *         It must be a single expression and must not start with a tag.
     * \param mtag    tag to use, or 0 to generate one.
     * \param mmod    modifier to use on the tag, or 0 for none.
     * \return the resulting message, or 0 in case of error.
     */
    UMessage*
    syncGet_(const char* expression, va_list& arg,
	     const send_options& = send_options::default_options);

  public:
    /// Synchronously evaluate an Urbi expression. The expression must
    /// not start with a tag or channel.
    UMessage* syncGet(const char* expression, ...);

    /// Synchronously evaluate an Urbi expression. The expression must
    /// not start with a tag or channel.
    UMessage* syncGet(const std::string& exp);

    /// Likewise, with a timeout.
    UMessage* syncGet(libport::utime_t useconds,
                      const char* expression, ...);
    /// Synchronously evaluate an Urbi expression, specifying the tag
    /// and modifiers to prepend to it.
    UMessage* syncGetTag(const char* expression,
                         const char* mtag, const char* mmod, ...);
    /// Likewise, with timeout.
    UMessage* syncGetTag(libport::utime_t useconds,
                         const char* expression,
                         const char* mtag, const char* mmod, ...);

    /// Send given buffer without copying it.
    int syncSend(const void* buffer, size_t length);

    /// Get an image in a synchronous way.
    /// \return 1 on success, 0 on failure.
    int syncGetImage(const char* cameraDevice, void* buffer,
                     size_t& buffersize,
		     int format, int transmitFormat,
                     size_t& width, size_t& height,
                     libport::utime_t useconds = 0);

    /// Get the value of any device in a synchronous way.
    /// \return 1 on success, 0 on failure.
    int syncGetValue(const char* valName, UValue& val,
		     libport::utime_t useconds = 0);
    int syncGetValue(const char* tag, const char* valName, UValue& val,
		     libport::utime_t useconds = 0);

    /// Get the value of device.val in a synchronous way.
    /// \return 1 on success, 0 on failure.
    int syncGetDevice(const char* device, double &val,
		      libport::utime_t useconds = 0);

    /// Execute an URBI command, return the resulting double
    /// value.
    /// \return 1 on success, 0 on failure.
    int syncGetResult(const char* command, double &val,
		      libport::utime_t useconds = 0);

    /// Get the normalized value of a device in a synchronous
    /// way.
    /// \return 1 on success, 0 on failure.
    int syncGetNormalizedDevice(const char* device, double &val,
				libport::utime_t useconds = 0);

    /// Get a field of a device in a synchronous way.
    /// \return 1 on success, 0 on failure.
    int syncGetDevice(const char* device, const char* field, double &val,
		      libport::utime_t useconds = 0);

    /// Get sound for duration milliseconds in buffer.
    int syncGetSound(const char* device, int duration, USound &sound,
		     libport::utime_t useconds = 0);

    /// Wait until a message with specified tag is received. Returned
    /// message must be deleted.
    UMessage* waitForTag(const std::string& tag, libport::utime_t useconds = 0);
    /// Overriding UAbstractclient implementation
    virtual void notifyCallbacks(const UMessage &msg);

    /**
     * Check message queue for pending messages, notify callbacks synchronously.
     * @param timeout If different -1 process events for at most @a timeout
     *                microseconds. This is useful if you don't want
     *                processEvents() to take to much time if there are many
     *                many pending messages.
     * @return true if at least one message was processed, false otherwise.
     * Callbacks functions are called synchronously in the caller thread.
     */
    bool processEvents(libport::utime_t timeout = -1);

    /**
     *  Stop the callback processing thread.
     *  The user is responsible for calling processEvents() regularily
     *  once this function has been called.
     */
    void stopCallbackThread();
    void callbackThread();

    /**
     * Block until kernel version is available, or an error occurrs.
     * @param hasProcessingThread true if a processing thread is running, false
     * if processEvents must be called while waiting.
     */
    using super_type::waitForKernelVersion;
    void waitForKernelVersion(bool hasProcessingThread);

    void setDefaultOptions(const send_options& opt);
    const send_options& getOptions(const send_options& opt =
                                   send_options::default_options) const;

    /**
     * Listen on the specified host:port pair. Bind an USyncClient on each
     * connection, and call \b connectCallback. Socket ownership is transfered
     * to the callback.
     * @return a handle on the listening socket. Destroy it to stop listening.
     */
    static boost::shared_ptr<libport::Finally>
    listen(const std::string& host, const std::string& port,
           boost::system::error_code& erc,
           connect_callback_type connectCallback,
           size_t buflen = URBI_BUFLEN,
           bool startCallbackThread = true);

    virtual void onConnect();

  protected:
    int joinCallbackThread_();

    static libport::Socket* onAccept(connect_callback_type l, size_t buflen,
                                     bool startThread);
    // Incremented at each queue push, decremented on pop.
    libport::Semaphore sem_;
    // Semaphore to delay execution of callback thread until ctor finishes.
    libport::Semaphore callbackSem_;

    // The list of incoming messages waiting to be processed.
    std::list<UMessage*> queue;
    libport::Lockable queueLock_;

    /// When locked waiting for a specific tag, notifyCallbacks will
    /// store the received message here, and waitForTag will get it
    /// there.
    UMessage* message_;
    libport::Semaphore syncLock_;
    std::string syncTag;

    send_options default_options_;

    bool stopCallbackThread_;
    pthread_t cbThread;
    // Used to block until the callback thread is realy stopped.
    libport::Semaphore stopCallbackSem_;
    connect_callback_type connectCallback_;
    // True if waitForTag is waiting from the polling thread.
    bool waitingFromPollThread_;
  };

} // namespace urbi

#endif // ! URBI_USYNCCLIENT_HH
<commit_msg>Fix typo.<commit_after>/*
 * Copyright (C) 2004, 2006-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file urbi/usyncclient.hh
/// \brief Definition of the URBI interface class

#ifndef URBI_USYNCCLIENT_HH
# define URBI_USYNCCLIENT_HH

# include <libport/finally.hh>
# include <libport/fwd.hh>
# include <libport/lockable.hh>
# include <libport/semaphore.hh>
# include <libport/utime.hh>
# include <libport/pthread.h>

# include <urbi/uclient.hh>

namespace urbi
{
  /*! Format in which image requested with syncGetSound are transmitted*/
  enum UTransmitFormat
  {
    /// Transmit images compressed in JPEG.
    URBI_TRANSMIT_JPEG,
    /// Transmit raw YCbCr images.
    URBI_TRANSMIT_YCbCr
  };

  /// UClient linux implementation with support for synchronous extra
  /// functions.
  /*! This class provides extra functions to synchronously request
     values. These functions can safely be called frow within a
     callback function.

     All callbacks will be called in a separate thread created in the
     constructor.
     When one of those callbacks calls a synchronous function, new incoming
     messages are kept on hold until the response from the synchronous call
     is received.

     If you want to call these callbacks in a different
     thread, call @stopCallbackThread, then regularly call
     @processEvents. Each call will call callbacks for all pending
     messages in the current thread.  */
  class URBI_SDK_API USyncClient: public UClient
  {
  public:
    typedef boost::function1<void, USyncClient*> connect_callback_type;
    typedef UClient super_type;
    typedef super_type::error_type error_type;

    /// Option structure for USyncClient construction.
    ///
    /// In addition to UClient::options, provides:
    /// - startCallbackThread
    /// - connectCallback.
    struct URBI_SDK_API options
      : public super_type::options
    {
      options();
      /// If true, create a thread dedicated to the processing of
      /// incoming messages. If false, it is the responsibility of the
      /// user to regularly call processEvents().  Defaults to true.
      UCLIENT_OPTION(bool, startCallbackThread);
      /// Ignore host and port if set, do not connect or listen.
      /// Called when connection is established.
      UCLIENT_OPTION(connect_callback_type, connectCallback);
    };

    /** Create a new connection to an Urbi Server. Blocks until the connection
     * is established.
     *
     *  \param host    The host to connect to.
     *  \param port    the port number to connect to, defaults to URBI_PORT.
     *  \param buflen  Size of reception buffer, defaults to URBI_BUFLEN.
     *  \param opt     Parameters of this USyncClient.
     */
    USyncClient(const std::string& host,
		unsigned port = URBI_PORT,
		size_t buflen = URBI_BUFLEN,
                const options& opt = options());

    ~USyncClient();

    /// Options for send(), rather than multiplying the overloads.
    struct send_options
    {
      send_options();

      send_options& timeout(libport::utime_t);
      send_options& tag(const char*, const char* = 0);

      /// Timeout in microseconds
      libport::utime_t timeout_;
      const char* mtag_;
      const char* mmod_;
      static const send_options default_options;
    };

  protected:
    virtual error_type onClose ();

  protected:
    /** Synchronously ask the server for the value of an expression.
     * \param expression   the Urbi expression to evaluate.
     *         It must be a single expression and must not start with a tag.
     * \param mtag    tag to use, or 0 to generate one.
     * \param mmod    modifier to use on the tag, or 0 for none.
     * \return the resulting message, or 0 in case of error.
     */
    UMessage*
    syncGet_(const char* expression, va_list& arg,
	     const send_options& = send_options::default_options);

  public:
    /// Synchronously evaluate an Urbi expression. The expression must
    /// not start with a tag or channel.
    UMessage* syncGet(const char* expression, ...);

    /// Synchronously evaluate an Urbi expression. The expression must
    /// not start with a tag or channel.
    UMessage* syncGet(const std::string& exp);

    /// Likewise, with a timeout.
    UMessage* syncGet(libport::utime_t useconds,
                      const char* expression, ...);
    /// Synchronously evaluate an Urbi expression, specifying the tag
    /// and modifiers to prepend to it.
    UMessage* syncGetTag(const char* expression,
                         const char* mtag, const char* mmod, ...);
    /// Likewise, with timeout.
    UMessage* syncGetTag(libport::utime_t useconds,
                         const char* expression,
                         const char* mtag, const char* mmod, ...);

    /// Send given buffer without copying it.
    int syncSend(const void* buffer, size_t length);

    /// Get an image in a synchronous way.
    /// \return 1 on success, 0 on failure.
    int syncGetImage(const char* cameraDevice, void* buffer,
                     size_t& buffersize,
		     int format, int transmitFormat,
                     size_t& width, size_t& height,
                     libport::utime_t useconds = 0);

    /// Get the value of any device in a synchronous way.
    /// \return 1 on success, 0 on failure.
    int syncGetValue(const char* valName, UValue& val,
		     libport::utime_t useconds = 0);
    int syncGetValue(const char* tag, const char* valName, UValue& val,
		     libport::utime_t useconds = 0);

    /// Get the value of device.val in a synchronous way.
    /// \return 1 on success, 0 on failure.
    int syncGetDevice(const char* device, double &val,
		      libport::utime_t useconds = 0);

    /// Execute an URBI command, return the resulting double
    /// value.
    /// \return 1 on success, 0 on failure.
    int syncGetResult(const char* command, double &val,
		      libport::utime_t useconds = 0);

    /// Get the normalized value of a device in a synchronous
    /// way.
    /// \return 1 on success, 0 on failure.
    int syncGetNormalizedDevice(const char* device, double &val,
				libport::utime_t useconds = 0);

    /// Get a field of a device in a synchronous way.
    /// \return 1 on success, 0 on failure.
    int syncGetDevice(const char* device, const char* field, double &val,
		      libport::utime_t useconds = 0);

    /// Get sound for duration milliseconds in buffer.
    int syncGetSound(const char* device, int duration, USound &sound,
		     libport::utime_t useconds = 0);

    /// Wait until a message with specified tag is received. Returned
    /// message must be deleted.
    UMessage* waitForTag(const std::string& tag, libport::utime_t useconds = 0);
    /// Overriding UAbstractclient implementation
    virtual void notifyCallbacks(const UMessage &msg);

    /**
     * Check message queue for pending messages, notify callbacks synchronously.
     * @param timeout If different -1 process events for at most @a timeout
     *                microseconds. This is useful if you don't want
     *                processEvents() to take to much time if there are many
     *                many pending messages.
     * @return true if at least one message was processed, false otherwise.
     * Callbacks functions are called synchronously in the caller thread.
     */
    bool processEvents(libport::utime_t timeout = -1);

    /**
     *  Stop the callback processing thread.
     *  The user is responsible for calling processEvents() regularily
     *  once this function has been called.
     */
    void stopCallbackThread();
    void callbackThread();

    /**
     * Block until kernel version is available, or an error occurrs.
     * @param hasProcessingThread true if a processing thread is running, false
     * if processEvents must be called while waiting.
     */
    using super_type::waitForKernelVersion;
    void waitForKernelVersion(bool hasProcessingThread);

    void setDefaultOptions(const send_options& opt);
    const send_options& getOptions(const send_options& opt =
                                   send_options::default_options) const;

    /**
     * Listen on the specified host:port pair. Bind an USyncClient on each
     * connection, and call \b connectCallback. Socket ownership is transfered
     * to the callback.
     * @return a handle on the listening socket. Destroy it to stop listening.
     */
    static boost::shared_ptr<libport::Finally>
    listen(const std::string& host, const std::string& port,
           boost::system::error_code& erc,
           connect_callback_type connectCallback,
           size_t buflen = URBI_BUFLEN,
           bool startCallbackThread = true);

    virtual void onConnect();

  protected:
    int joinCallbackThread_();

    static libport::Socket* onAccept(connect_callback_type l, size_t buflen,
                                     bool startThread);
    // Incremented at each queue push, decremented on pop.
    libport::Semaphore sem_;
    // Semaphore to delay execution of callback thread until ctor finishes.
    libport::Semaphore callbackSem_;

    // The list of incoming messages waiting to be processed.
    std::list<UMessage*> queue;
    libport::Lockable queueLock_;

    /// When locked waiting for a specific tag, notifyCallbacks will
    /// store the received message here, and waitForTag will get it
    /// there.
    UMessage* message_;
    libport::Semaphore syncLock_;
    std::string syncTag;

    send_options default_options_;

    bool stopCallbackThread_;
    pthread_t cbThread;
    // Used to block until the callback thread is realy stopped.
    libport::Semaphore stopCallbackSem_;
    connect_callback_type connectCallback_;
    // True if waitForTag is waiting from the polling thread.
    bool waitingFromPollThread_;
  };

} // namespace urbi

#endif // ! URBI_USYNCCLIENT_HH
<|endoftext|>


<commit_before>//  The MIT License (MIT)
//
//  Copyright (c) 2016 Tag Games Limited
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#include <Keyboard/KeyboardPresenter.h>

#include <Common/UI/BasicWidgetFactory.h>

#include <ChilliSource/Core/Base.h>
#include <ChilliSource/Core/Resource.h>
#include <ChilliSource/Core/State.h>
#include <ChilliSource/Core/Math/Vector3.h>
#include <ChilliSource/Input/Keyboard.h>
#include <ChilliSource/Rendering/Font.h>
#include <ChilliSource/UI/Base.h>
#include <ChilliSource/UI/Text.h>

namespace CSTest
{
    namespace Keyboard
    {
        CS_DEFINE_NAMEDTYPE(KeyboardPresenter);

        //------------------------------------------------------------------------------
        KeyboardPresenterUPtr KeyboardPresenter::Create() noexcept
        {
            return KeyboardPresenterUPtr(new KeyboardPresenter());
        }

        //------------------------------------------------------------------------------
        bool KeyboardPresenter::IsA(CS::InterfaceIDType interfaceId) const noexcept
        {
            return (KeyboardPresenter::InterfaceID == interfaceId);
        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::InitUI() noexcept
        {
            auto resourcePool = CS::Application::Get()->GetResourcePool();
            auto smallFont = resourcePool->LoadResource<CS::Font>(CS::StorageLocation::k_package, "Fonts/ArialSmall.csfont");

            auto basicWidgetFactory = CS::Application::Get()->GetSystem<Common::BasicWidgetFactory>();
            auto label = basicWidgetFactory->CreateLabel(CS::Vector2(0.9f, 0.8f), smallFont, "", CS::AlignmentAnchor::k_middleCentre,
                                                         CS::HorizontalTextJustification::k_left, CS::VerticalTextJustification::k_top);
            m_textComponent = label->GetComponent<CS::TextUIComponent>();

            auto uiCanvas = GetState()->GetUICanvas();
            uiCanvas->AddWidget(std::move(label));
        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::AddKeyPressHandler() noexcept
        {
            auto keyboardSystem = CS::Application::Get()->GetSystem<CS::Keyboard>();

            if (keyboardSystem == nullptr)
            {
                m_textComponent->SetText("No Keyboard.");
                return;
            }

            m_eventConnections.push_back(keyboardSystem->GetKeyPressedEvent().OpenConnection([=](CS::KeyCode keyPressed, std::vector<CS::ModifierKeyCode> modifiers)
            {
                m_keysHeld.push_back(keyPressed);
                DisplayKeys();
            }));
        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::AddKeyReleaseHandler() noexcept
        {
            auto keyboardSystem = CS::Application::Get()->GetSystem<CS::Keyboard>();
            CS_ASSERT(keyboardSystem, "No keyboard detected.");

            m_eventConnections.push_back(keyboardSystem->GetKeyReleasedEvent().OpenConnection([=](CS::KeyCode keyReleased)
            {
                auto findIterator = std::find(m_keysHeld.begin(), m_keysHeld.end(), keyReleased);
                if (findIterator != m_keysHeld.end())
                {
                    m_keysHeld.erase(findIterator);
                }

                DisplayKeys();
            }));

        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::DisplayKeys() noexcept
        {
            std::string text = "Keys Held: ";
            bool first = true;
            for (auto key : m_keysHeld)
            {
                if (!first)
                {
                    text += ", ";
                }

                first = false;
                text += CS::GetKeyName(key);
            }

            m_textComponent->SetText(text);
        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::OnInit() noexcept
        {
            InitUI();
            DisplayKeys();
            AddKeyPressHandler();
            AddKeyReleaseHandler();
        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::OnDestroy() noexcept
        {
            m_eventConnections.clear();
        }
    }
}<commit_msg>Assert for no keyboard added.<commit_after>//  The MIT License (MIT)
//
//  Copyright (c) 2016 Tag Games Limited
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#include <Keyboard/KeyboardPresenter.h>

#include <Common/UI/BasicWidgetFactory.h>

#include <ChilliSource/Core/Base.h>
#include <ChilliSource/Core/Resource.h>
#include <ChilliSource/Core/State.h>
#include <ChilliSource/Core/Math/Vector3.h>
#include <ChilliSource/Input/Keyboard.h>
#include <ChilliSource/Rendering/Font.h>
#include <ChilliSource/UI/Base.h>
#include <ChilliSource/UI/Text.h>

namespace CSTest
{
    namespace Keyboard
    {
        CS_DEFINE_NAMEDTYPE(KeyboardPresenter);

        //------------------------------------------------------------------------------
        KeyboardPresenterUPtr KeyboardPresenter::Create() noexcept
        {
            return KeyboardPresenterUPtr(new KeyboardPresenter());
        }

        //------------------------------------------------------------------------------
        bool KeyboardPresenter::IsA(CS::InterfaceIDType interfaceId) const noexcept
        {
            return (KeyboardPresenter::InterfaceID == interfaceId);
        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::InitUI() noexcept
        {
            auto resourcePool = CS::Application::Get()->GetResourcePool();
            auto smallFont = resourcePool->LoadResource<CS::Font>(CS::StorageLocation::k_package, "Fonts/ArialSmall.csfont");

            auto basicWidgetFactory = CS::Application::Get()->GetSystem<Common::BasicWidgetFactory>();
            auto label = basicWidgetFactory->CreateLabel(CS::Vector2(0.9f, 0.8f), smallFont, "", CS::AlignmentAnchor::k_middleCentre,
                                                         CS::HorizontalTextJustification::k_left, CS::VerticalTextJustification::k_top);
            m_textComponent = label->GetComponent<CS::TextUIComponent>();

            auto uiCanvas = GetState()->GetUICanvas();
            uiCanvas->AddWidget(std::move(label));
        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::AddKeyPressHandler() noexcept
        {
            auto keyboardSystem = CS::Application::Get()->GetSystem<CS::Keyboard>();
            CS_ASSERT(keyboardSystem, "No keyboard detected.");

            m_eventConnections.push_back(keyboardSystem->GetKeyPressedEvent().OpenConnection([=](CS::KeyCode keyPressed, std::vector<CS::ModifierKeyCode> modifiers)
            {
                m_keysHeld.push_back(keyPressed);
                DisplayKeys();
            }));
        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::AddKeyReleaseHandler() noexcept
        {
            auto keyboardSystem = CS::Application::Get()->GetSystem<CS::Keyboard>();
            CS_ASSERT(keyboardSystem, "No keyboard detected.");

            m_eventConnections.push_back(keyboardSystem->GetKeyReleasedEvent().OpenConnection([=](CS::KeyCode keyReleased)
            {
                auto findIterator = std::find(m_keysHeld.begin(), m_keysHeld.end(), keyReleased);
                if (findIterator != m_keysHeld.end())
                {
                    m_keysHeld.erase(findIterator);
                }

                DisplayKeys();
            }));

        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::DisplayKeys() noexcept
        {
            std::string text = "Keys Held: ";
            bool first = true;
            for (auto key : m_keysHeld)
            {
                if (!first)
                {
                    text += ", ";
                }

                first = false;
                text += CS::GetKeyName(key);
            }

            m_textComponent->SetText(text);
        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::OnInit() noexcept
        {
            InitUI();
            DisplayKeys();
            AddKeyPressHandler();
            AddKeyReleaseHandler();
        }

        //------------------------------------------------------------------------------
        void KeyboardPresenter::OnDestroy() noexcept
        {
            m_eventConnections.clear();
        }
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2017 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Winsock2.h>
#include <iostream>

#define UNUSED(x) ((void)x)

int make_fdpair(int& w, int& r) {
  struct sockaddr_in addr = {0};
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

  int listener = socket(AF_INET, SOCK_STREAM, 0);
  bind(listener, (const struct sockaddr*)&addr, sizeof(addr));
  listen(listener, 1);
  int addrlen = sizeof(addr);
  getsockname(listener, (struct sockaddr*)&addr, &addrlen);

  w = socket(AF_INET, SOCK_STREAM, 0);
  connect(w, (struct sockaddr*)&addr, sizeof(addr));
  r = accept(listener, NULL, NULL);

  closesocket(listener);
  return 0;
}

int main(int argc, char* argv[]) {
  UNUSED(argc);
  UNUSED(argv);
  WSADATA wd;
  WSAStartup(MAKEWORD(2, 2), &wd);

  static const int RUN_TIMES = 100;
  int w;
  int r;
  make_fdpair(w, r);

  for (int i = 0; i < RUN_TIMES; ++i) {
    char wbuf[8] = "Wakeup!";
    send(w, wbuf, sizeof(wbuf), 0);

    char rbuf[8] = {0};
    recv(r, rbuf, sizeof(rbuf), 0);
    std::cout << "[" << i+1 << "] read buffer is : " << rbuf << std::endl;
  }

  WSACleanup();
  return 0;
}
<commit_msg>:hammer: refactor(eventfd): refactoring the implementation of eventfd for windows platform<commit_after>// Copyright (c) 2017 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Winsock2.h>
#include <iostream>

#define UNUSED(x) ((void)x)

struct _EventFd_t {
  int writer{};
  int reader{};

  bool is_valid(void) const {
    return writer > 0 && reader > 0;
  }

  _EventFd_t& operator=(std::nullptr_t) {
    writer = 0;
    reader = 0;
  }
};

void eventfd_close(_EventFd_t eventfd) {
  if (eventfd.reader > 0)
    closesocket(eventfd.reader);
  if (eventfd.writer > 0)
    closesocket(eventfd.writer);
}

_EventFd_t eventfd_create(void) {
  struct sockaddr_in addr{};
  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  addr.sin_family = AF_INET;

  bool has_error = false;
  _EventFd_t eventfd{};
  int listener = socket(AF_INET, SOCK_STREAM, 0);
  if (listener < 0)
    return eventfd;

  int r = bind(listener, (const struct sockaddr*)&addr, sizeof(addr));
  if (0 == r) {
    int addrlen = sizeof(addr);
    r = getsockname(listener, (struct sockaddr*)&addr, &addrlen);
  }
  if (0 == r)
    r = listen(listener, 1);

  eventfd.writer = socket(AF_INET, SOCK_STREAM, 0);
  if (eventfd.writer < 0)
    goto Exit;
  if (0 == r)
    r = connect(eventfd.writer, (struct sockaddr*)&addr, sizeof(addr));
  if (0 == r)
    eventfd.reader = accept(listener, nullptr, nullptr);
  if (eventfd.reader <= 0)
    has_error = true;

Exit:
  if (has_error)
    eventfd_close(eventfd);
  if (listener > 0)
    closesocket(listener);

  return eventfd;
}

int eventfd_read(_EventFd_t eventfd, char* buf, size_t len) {
  return recv(eventfd.reader, buf, len, 0);
}

int eventfd_write(_EventFd_t eventfd, const char* buf, size_t len) {
  return send(eventfd.writer, buf, len, 0);
}

int main(int argc, char* argv[]) {
  UNUSED(argc);
  UNUSED(argv);
  WSADATA wd;
  WSAStartup(MAKEWORD(2, 2), &wd);

  static const int RUN_TIMES = 100;
  _EventFd_t eventfd = eventfd_create();

  for (int i = 0; i < RUN_TIMES; ++i) {
    char wbuf[8] = "Wakeup!";
    eventfd_write(eventfd, wbuf, sizeof(wbuf));

    char rbuf[8] = {0};
    eventfd_read(eventfd, rbuf, sizeof(rbuf));
    std::cout << "[" << i+1 << "] read buffer is : " << rbuf << std::endl;
  }

  eventfd_close(eventfd);

  WSACleanup();
  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2003, 2006, 2007 Apple Inc.  All rights reserved.
 * Copyright (C) 2007-2009 Torch Mobile, Inc.
 * Copyright (C) 2011 University of Szeged. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// The vprintf_stderr_common function triggers this error in the Mac build.
// Feel free to remove this pragma if this file builds on Mac.
// According to http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas
// we need to place this directive before any data or functions are defined.
#pragma GCC diagnostic ignored "-Wmissing-format-attribute"

#include "config.h"
#include "Assertions.h"

#include "Compiler.h"
#include "OwnPtr.h"
#include "PassOwnPtr.h"

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#if HAVE(SIGNAL_H)
#include <signal.h>
#endif

#if USE(CF)
#include <AvailabilityMacros.h>
#include <CoreFoundation/CFString.h>
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
#define WTF_USE_APPLE_SYSTEM_LOG 1
#include <asl.h>
#endif
#endif // USE(CF)

#if COMPILER(MSVC)
#include <crtdbg.h>
#endif

#if OS(WIN)
#include <windows.h>
#define HAVE_ISDEBUGGERPRESENT 1
#endif

#if OS(MACOSX) || (OS(LINUX) && !defined(__UCLIBC__))
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
#endif

#if OS(ANDROID)
#include <android/log.h>
#endif

extern "C" {

WTF_ATTRIBUTE_PRINTF(1, 0)
static void vprintf_stderr_common(const char* format, va_list args)
{
#if USE(CF) && !OS(WIN)
    if (strstr(format, "%@")) {
        CFStringRef cfFormat = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8);

#if COMPILER(CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif
        CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, cfFormat, args);
#if COMPILER(CLANG)
#pragma clang diagnostic pop
#endif
        CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8);
        char* buffer = (char*)malloc(length + 1);

        CFStringGetCString(str, buffer, length, kCFStringEncodingUTF8);

#if USE(APPLE_SYSTEM_LOG)
        asl_log(0, 0, ASL_LEVEL_NOTICE, "%s", buffer);
#endif
        fputs(buffer, stderr);

        free(buffer);
        CFRelease(str);
        CFRelease(cfFormat);
        return;
    }

#if USE(APPLE_SYSTEM_LOG)
    va_list copyOfArgs;
    va_copy(copyOfArgs, args);
    asl_vlog(0, 0, ASL_LEVEL_NOTICE, format, copyOfArgs);
    va_end(copyOfArgs);
#endif

    // Fall through to write to stderr in the same manner as other platforms.

#elif OS(ANDROID)
    __android_log_vprint(ANDROID_LOG_WARN, "WebKit", format, args);
#elif HAVE(ISDEBUGGERPRESENT)
    if (IsDebuggerPresent()) {
        size_t size = 1024;

        do {
            char* buffer = (char*)malloc(size);

            if (buffer == NULL)
                break;

            if (_vsnprintf(buffer, size, format, args) != -1) {
                OutputDebugStringA(buffer);
                free(buffer);
                break;
            }

            free(buffer);
            size *= 2;
        } while (size > 1024);
    }
#endif
    vfprintf(stderr, format, args);
}

#if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif

static void vprintf_stderr_with_prefix(const char* prefix, const char* format, va_list args)
{
    size_t prefixLength = strlen(prefix);
    size_t formatLength = strlen(format);
    OwnPtr<char[]> formatWithPrefix = adoptArrayPtr(new char[prefixLength + formatLength + 1]);
    memcpy(formatWithPrefix.get(), prefix, prefixLength);
    memcpy(formatWithPrefix.get() + prefixLength, format, formatLength);
    formatWithPrefix[prefixLength + formatLength] = 0;

    vprintf_stderr_common(formatWithPrefix.get(), args);
}

static void vprintf_stderr_with_trailing_newline(const char* format, va_list args)
{
    size_t formatLength = strlen(format);
    if (formatLength && format[formatLength - 1] == '\n') {
        vprintf_stderr_common(format, args);
        return;
    }

    OwnPtr<char[]> formatWithNewline = adoptArrayPtr(new char[formatLength + 2]);
    memcpy(formatWithNewline.get(), format, formatLength);
    formatWithNewline[formatLength] = '\n';
    formatWithNewline[formatLength + 1] = 0;

    vprintf_stderr_common(formatWithNewline.get(), args);
}

#if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
#pragma GCC diagnostic pop
#endif

WTF_ATTRIBUTE_PRINTF(1, 2)
static void printf_stderr_common(const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf_stderr_common(format, args);
    va_end(args);
}

static void printCallSite(const char* file, int line, const char* function)
{
#if OS(WIN) && defined(_DEBUG)
    _CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function);
#else
    // By using this format, which matches the format used by MSVC for compiler errors, developers
    // using Visual Studio can double-click the file/line number in the Output Window to have the
    // editor navigate to that line of code. It seems fine for other developers, too.
    printf_stderr_common("%s(%d) : %s\n", file, line, function);
#endif
}

void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion)
{
    if (assertion)
        printf_stderr_common("ASSERTION FAILED: %s\n", assertion);
    else
        printf_stderr_common("SHOULD NEVER BE REACHED\n");
    printCallSite(file, line, function);
}

void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf_stderr_with_prefix("ASSERTION FAILED: ", format, args);
    va_end(args);
    printf_stderr_common("\n%s\n", assertion);
    printCallSite(file, line, function);
}

void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion)
{
    printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion);
    printCallSite(file, line, function);
}

void WTFGetBacktrace(void** stack, int* size)
{
#if OS(MACOSX) || (OS(LINUX) && !defined(__UCLIBC__))
    *size = backtrace(stack, *size);
#elif OS(WIN)
    // The CaptureStackBackTrace function is available in XP, but it is not defined
    // in the Windows Server 2003 R2 Platform SDK. So, we'll grab the function
    // through GetProcAddress.
    typedef WORD (NTAPI* RtlCaptureStackBackTraceFunc)(DWORD, DWORD, PVOID*, PDWORD);
    HMODULE kernel32 = ::GetModuleHandleW(L"Kernel32.dll");
    if (!kernel32) {
        *size = 0;
        return;
    }
    RtlCaptureStackBackTraceFunc captureStackBackTraceFunc = reinterpret_cast<RtlCaptureStackBackTraceFunc>(
        ::GetProcAddress(kernel32, "RtlCaptureStackBackTrace"));
    if (captureStackBackTraceFunc)
        *size = captureStackBackTraceFunc(0, *size, stack, 0);
    else
        *size = 0;
#else
    *size = 0;
#endif
}

void WTFReportBacktrace(int framesToShow)
{
    static const int framesToSkip = 2;
    // Use alloca to allocate on the stack since this function is used in OOM situations.
    void** samples = static_cast<void**>(alloca((framesToShow + framesToSkip) * sizeof(void *)));
    int frames = framesToShow + framesToSkip;

    WTFGetBacktrace(samples, &frames);
    WTFPrintBacktrace(samples + framesToSkip, frames - framesToSkip);
}

void WTFPrintBacktrace(void** stack, int size)
{
    for (int i = 0; i < size; ++i) {
        const char* mangledName = 0;
        char* cxaDemangled = 0;
#if OS(MACOSX) || OS(LINUX)
        Dl_info info;
        if (dladdr(stack[i], &info) && info.dli_sname)
            mangledName = info.dli_sname;
        if (mangledName)
            cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0);
#endif
        const int frameNumber = i + 1;
        if (mangledName || cxaDemangled)
            printf_stderr_common("%-3d %p %s\n", frameNumber, stack[i], cxaDemangled ? cxaDemangled : mangledName);
        else
            printf_stderr_common("%-3d %p\n", frameNumber, stack[i]);
        free(cxaDemangled);
    }
}

static WTFCrashHookFunction globalHook = 0;

void WTFSetCrashHook(WTFCrashHookFunction function)
{
    globalHook = function;
}

void WTFInvokeCrashHook()
{
    if (globalHook)
        globalHook();
}

#if HAVE(SIGNAL_H)
static NO_RETURN void dumpBacktraceSignalHandler(int sig)
{
    WTFReportBacktrace();
    exit(128 + sig);
}

static void installSignalHandlersForFatalErrors(void (*handler)(int))
{
    signal(SIGILL, handler); //    4: illegal instruction (not reset when caught).
    signal(SIGTRAP, handler); //   5: trace trap (not reset when caught).
    signal(SIGFPE, handler); //    8: floating point exception.
    signal(SIGBUS, handler); //   10: bus error.
    signal(SIGSEGV, handler); //  11: segmentation violation.
    signal(SIGSYS, handler); //   12: bad argument to system call.
    signal(SIGPIPE, handler); //  13: write on a pipe with no reader.
    signal(SIGXCPU, handler); //  24: exceeded CPU time limit.
    signal(SIGXFSZ, handler); //  25: exceeded file size limit.
}

static void resetSignalHandlersForFatalErrors()
{
    installSignalHandlersForFatalErrors(SIG_DFL);
}
#endif

void WTFInstallReportBacktraceOnCrashHook()
{
#if HAVE(SIGNAL_H)
    // Needed otherwise we are going to dump the stack trace twice
    // in case we hit an assertion.
    WTFSetCrashHook(&resetSignalHandlersForFatalErrors);
    installSignalHandlersForFatalErrors(&dumpBacktraceSignalHandler);
#endif
}

void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf_stderr_with_prefix("FATAL ERROR: ", format, args);
    va_end(args);
    printf_stderr_common("\n");
    printCallSite(file, line, function);
}

void WTFReportError(const char* file, int line, const char* function, const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf_stderr_with_prefix("ERROR: ", format, args);
    va_end(args);
    printf_stderr_common("\n");
    printCallSite(file, line, function);
}

void WTFLog(WTFLogChannel* channel, const char* format, ...)
{
    if (channel->state != WTFLogChannelOn)
        return;

    va_list args;
    va_start(args, format);
    vprintf_stderr_with_trailing_newline(format, args);
    va_end(args);
}

void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...)
{
    if (channel->state != WTFLogChannelOn)
        return;

    va_list args;
    va_start(args, format);
    vprintf_stderr_with_trailing_newline(format, args);
    va_end(args);

    printCallSite(file, line, function);
}

void WTFLogAlways(const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf_stderr_with_trailing_newline(format, args);
    va_end(args);
}

} // extern "C"
<commit_msg>don't use abi::__cxa_demangle in uclibc builds<commit_after>/*
 * Copyright (C) 2003, 2006, 2007 Apple Inc.  All rights reserved.
 * Copyright (C) 2007-2009 Torch Mobile, Inc.
 * Copyright (C) 2011 University of Szeged. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// The vprintf_stderr_common function triggers this error in the Mac build.
// Feel free to remove this pragma if this file builds on Mac.
// According to http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas
// we need to place this directive before any data or functions are defined.
#pragma GCC diagnostic ignored "-Wmissing-format-attribute"

#include "config.h"
#include "Assertions.h"

#include "Compiler.h"
#include "OwnPtr.h"
#include "PassOwnPtr.h"

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#if HAVE(SIGNAL_H)
#include <signal.h>
#endif

#if USE(CF)
#include <AvailabilityMacros.h>
#include <CoreFoundation/CFString.h>
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
#define WTF_USE_APPLE_SYSTEM_LOG 1
#include <asl.h>
#endif
#endif // USE(CF)

#if COMPILER(MSVC)
#include <crtdbg.h>
#endif

#if OS(WIN)
#include <windows.h>
#define HAVE_ISDEBUGGERPRESENT 1
#endif

#if OS(MACOSX) || (OS(LINUX) && !defined(__UCLIBC__))
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
#endif

#if OS(ANDROID)
#include <android/log.h>
#endif

extern "C" {

WTF_ATTRIBUTE_PRINTF(1, 0)
static void vprintf_stderr_common(const char* format, va_list args)
{
#if USE(CF) && !OS(WIN)
    if (strstr(format, "%@")) {
        CFStringRef cfFormat = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8);

#if COMPILER(CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif
        CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, cfFormat, args);
#if COMPILER(CLANG)
#pragma clang diagnostic pop
#endif
        CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8);
        char* buffer = (char*)malloc(length + 1);

        CFStringGetCString(str, buffer, length, kCFStringEncodingUTF8);

#if USE(APPLE_SYSTEM_LOG)
        asl_log(0, 0, ASL_LEVEL_NOTICE, "%s", buffer);
#endif
        fputs(buffer, stderr);

        free(buffer);
        CFRelease(str);
        CFRelease(cfFormat);
        return;
    }

#if USE(APPLE_SYSTEM_LOG)
    va_list copyOfArgs;
    va_copy(copyOfArgs, args);
    asl_vlog(0, 0, ASL_LEVEL_NOTICE, format, copyOfArgs);
    va_end(copyOfArgs);
#endif

    // Fall through to write to stderr in the same manner as other platforms.

#elif OS(ANDROID)
    __android_log_vprint(ANDROID_LOG_WARN, "WebKit", format, args);
#elif HAVE(ISDEBUGGERPRESENT)
    if (IsDebuggerPresent()) {
        size_t size = 1024;

        do {
            char* buffer = (char*)malloc(size);

            if (buffer == NULL)
                break;

            if (_vsnprintf(buffer, size, format, args) != -1) {
                OutputDebugStringA(buffer);
                free(buffer);
                break;
            }

            free(buffer);
            size *= 2;
        } while (size > 1024);
    }
#endif
    vfprintf(stderr, format, args);
}

#if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif

static void vprintf_stderr_with_prefix(const char* prefix, const char* format, va_list args)
{
    size_t prefixLength = strlen(prefix);
    size_t formatLength = strlen(format);
    OwnPtr<char[]> formatWithPrefix = adoptArrayPtr(new char[prefixLength + formatLength + 1]);
    memcpy(formatWithPrefix.get(), prefix, prefixLength);
    memcpy(formatWithPrefix.get() + prefixLength, format, formatLength);
    formatWithPrefix[prefixLength + formatLength] = 0;

    vprintf_stderr_common(formatWithPrefix.get(), args);
}

static void vprintf_stderr_with_trailing_newline(const char* format, va_list args)
{
    size_t formatLength = strlen(format);
    if (formatLength && format[formatLength - 1] == '\n') {
        vprintf_stderr_common(format, args);
        return;
    }

    OwnPtr<char[]> formatWithNewline = adoptArrayPtr(new char[formatLength + 2]);
    memcpy(formatWithNewline.get(), format, formatLength);
    formatWithNewline[formatLength] = '\n';
    formatWithNewline[formatLength + 1] = 0;

    vprintf_stderr_common(formatWithNewline.get(), args);
}

#if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
#pragma GCC diagnostic pop
#endif

WTF_ATTRIBUTE_PRINTF(1, 2)
static void printf_stderr_common(const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf_stderr_common(format, args);
    va_end(args);
}

static void printCallSite(const char* file, int line, const char* function)
{
#if OS(WIN) && defined(_DEBUG)
    _CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function);
#else
    // By using this format, which matches the format used by MSVC for compiler errors, developers
    // using Visual Studio can double-click the file/line number in the Output Window to have the
    // editor navigate to that line of code. It seems fine for other developers, too.
    printf_stderr_common("%s(%d) : %s\n", file, line, function);
#endif
}

void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion)
{
    if (assertion)
        printf_stderr_common("ASSERTION FAILED: %s\n", assertion);
    else
        printf_stderr_common("SHOULD NEVER BE REACHED\n");
    printCallSite(file, line, function);
}

void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf_stderr_with_prefix("ASSERTION FAILED: ", format, args);
    va_end(args);
    printf_stderr_common("\n%s\n", assertion);
    printCallSite(file, line, function);
}

void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion)
{
    printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion);
    printCallSite(file, line, function);
}

void WTFGetBacktrace(void** stack, int* size)
{
#if OS(MACOSX) || (OS(LINUX) && !defined(__UCLIBC__))
    *size = backtrace(stack, *size);
#elif OS(WIN)
    // The CaptureStackBackTrace function is available in XP, but it is not defined
    // in the Windows Server 2003 R2 Platform SDK. So, we'll grab the function
    // through GetProcAddress.
    typedef WORD (NTAPI* RtlCaptureStackBackTraceFunc)(DWORD, DWORD, PVOID*, PDWORD);
    HMODULE kernel32 = ::GetModuleHandleW(L"Kernel32.dll");
    if (!kernel32) {
        *size = 0;
        return;
    }
    RtlCaptureStackBackTraceFunc captureStackBackTraceFunc = reinterpret_cast<RtlCaptureStackBackTraceFunc>(
        ::GetProcAddress(kernel32, "RtlCaptureStackBackTrace"));
    if (captureStackBackTraceFunc)
        *size = captureStackBackTraceFunc(0, *size, stack, 0);
    else
        *size = 0;
#else
    *size = 0;
#endif
}

void WTFReportBacktrace(int framesToShow)
{
    static const int framesToSkip = 2;
    // Use alloca to allocate on the stack since this function is used in OOM situations.
    void** samples = static_cast<void**>(alloca((framesToShow + framesToSkip) * sizeof(void *)));
    int frames = framesToShow + framesToSkip;

    WTFGetBacktrace(samples, &frames);
    WTFPrintBacktrace(samples + framesToSkip, frames - framesToSkip);
}

void WTFPrintBacktrace(void** stack, int size)
{
    for (int i = 0; i < size; ++i) {
        const char* mangledName = 0;
        char* cxaDemangled = 0;
#if OS(MACOSX) || (OS(LINUX) && !defined(__UCLIBC__))
        Dl_info info;
        if (dladdr(stack[i], &info) && info.dli_sname)
            mangledName = info.dli_sname;
        if (mangledName)
            cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0);
#endif
        const int frameNumber = i + 1;
        if (mangledName || cxaDemangled)
            printf_stderr_common("%-3d %p %s\n", frameNumber, stack[i], cxaDemangled ? cxaDemangled : mangledName);
        else
            printf_stderr_common("%-3d %p\n", frameNumber, stack[i]);
        free(cxaDemangled);
    }
}

static WTFCrashHookFunction globalHook = 0;

void WTFSetCrashHook(WTFCrashHookFunction function)
{
    globalHook = function;
}

void WTFInvokeCrashHook()
{
    if (globalHook)
        globalHook();
}

#if HAVE(SIGNAL_H)
static NO_RETURN void dumpBacktraceSignalHandler(int sig)
{
    WTFReportBacktrace();
    exit(128 + sig);
}

static void installSignalHandlersForFatalErrors(void (*handler)(int))
{
    signal(SIGILL, handler); //    4: illegal instruction (not reset when caught).
    signal(SIGTRAP, handler); //   5: trace trap (not reset when caught).
    signal(SIGFPE, handler); //    8: floating point exception.
    signal(SIGBUS, handler); //   10: bus error.
    signal(SIGSEGV, handler); //  11: segmentation violation.
    signal(SIGSYS, handler); //   12: bad argument to system call.
    signal(SIGPIPE, handler); //  13: write on a pipe with no reader.
    signal(SIGXCPU, handler); //  24: exceeded CPU time limit.
    signal(SIGXFSZ, handler); //  25: exceeded file size limit.
}

static void resetSignalHandlersForFatalErrors()
{
    installSignalHandlersForFatalErrors(SIG_DFL);
}
#endif

void WTFInstallReportBacktraceOnCrashHook()
{
#if HAVE(SIGNAL_H)
    // Needed otherwise we are going to dump the stack trace twice
    // in case we hit an assertion.
    WTFSetCrashHook(&resetSignalHandlersForFatalErrors);
    installSignalHandlersForFatalErrors(&dumpBacktraceSignalHandler);
#endif
}

void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf_stderr_with_prefix("FATAL ERROR: ", format, args);
    va_end(args);
    printf_stderr_common("\n");
    printCallSite(file, line, function);
}

void WTFReportError(const char* file, int line, const char* function, const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf_stderr_with_prefix("ERROR: ", format, args);
    va_end(args);
    printf_stderr_common("\n");
    printCallSite(file, line, function);
}

void WTFLog(WTFLogChannel* channel, const char* format, ...)
{
    if (channel->state != WTFLogChannelOn)
        return;

    va_list args;
    va_start(args, format);
    vprintf_stderr_with_trailing_newline(format, args);
    va_end(args);
}

void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...)
{
    if (channel->state != WTFLogChannelOn)
        return;

    va_list args;
    va_start(args, format);
    vprintf_stderr_with_trailing_newline(format, args);
    va_end(args);

    printCallSite(file, line, function);
}

void WTFLogAlways(const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf_stderr_with_trailing_newline(format, args);
    va_end(args);
}

} // extern "C"
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "config.h"
#include "modules/serviceworkers/ServiceWorkerContainer.h"

#include "bindings/core/v8/CallbackPromiseAdapter.h"
#include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/SerializedScriptValue.h"
#include "core/dom/DOMException.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/ExecutionContext.h"
#include "core/dom/MessagePort.h"
#include "core/events/MessageEvent.h"
#include "core/frame/LocalDOMWindow.h"
#include "modules/serviceworkers/ServiceWorker.h"
#include "modules/serviceworkers/ServiceWorkerContainerClient.h"
#include "modules/serviceworkers/ServiceWorkerError.h"
#include "modules/serviceworkers/ServiceWorkerRegistration.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "public/platform/WebServiceWorker.h"
#include "public/platform/WebServiceWorkerProvider.h"
#include "public/platform/WebServiceWorkerRegistration.h"
#include "public/platform/WebString.h"
#include "public/platform/WebURL.h"

namespace blink {

// This wraps CallbackPromiseAdapter and resolves the promise with undefined
// when nullptr is given to onSuccess.
class GetRegistrationCallback : public WebServiceWorkerProvider::WebServiceWorkerGetRegistrationCallbacks {
public:
    explicit GetRegistrationCallback(PassRefPtr<ScriptPromiseResolver> resolver)
        : m_resolver(resolver)
        , m_adapter(m_resolver) { }
    virtual ~GetRegistrationCallback() { }
    virtual void onSuccess(WebServiceWorkerRegistration* registration) override
    {
        if (registration)
            m_adapter.onSuccess(registration);
        else if (m_resolver->executionContext() && !m_resolver->executionContext()->activeDOMObjectsAreStopped())
            m_resolver->resolve();
    }
    virtual void onError(WebServiceWorkerError* error) override { m_adapter.onError(error); }
private:
    RefPtr<ScriptPromiseResolver> m_resolver;
    CallbackPromiseAdapter<ServiceWorkerRegistration, ServiceWorkerError> m_adapter;
    WTF_MAKE_NONCOPYABLE(GetRegistrationCallback);
};

ServiceWorkerContainer* ServiceWorkerContainer::create(ExecutionContext* executionContext)
{
    return new ServiceWorkerContainer(executionContext);
}

ServiceWorkerContainer::~ServiceWorkerContainer()
{
    ASSERT(!m_provider);
}

void ServiceWorkerContainer::willBeDetachedFromFrame()
{
    if (m_provider) {
        m_provider->setClient(0);
        m_provider = nullptr;
    }
}

void ServiceWorkerContainer::trace(Visitor* visitor)
{
    visitor->trace(m_controller);
    visitor->trace(m_readyRegistration);
    visitor->trace(m_ready);
}

ScriptPromise ServiceWorkerContainer::registerServiceWorker(ScriptState* scriptState, const String& url, const RegistrationOptions& options)
{
    ASSERT(RuntimeEnabledFeatures::serviceWorkerEnabled());
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    ScriptPromise promise = resolver->promise();

    if (!m_provider) {
        resolver->reject(DOMException::create(InvalidStateError, "No associated provider is available"));
        return promise;
    }

    // FIXME: This should use the container's execution context, not
    // the callers.
    ExecutionContext* executionContext = scriptState->executionContext();
    RefPtr<SecurityOrigin> documentOrigin = executionContext->securityOrigin();
    String errorMessage;
    if (!documentOrigin->canAccessFeatureRequiringSecureOrigin(errorMessage)) {
        resolver->reject(DOMException::create(NotSupportedError, errorMessage));
        return promise;
    }

    KURL pageURL = KURL(KURL(), documentOrigin->toString());
    if (!pageURL.protocolIsInHTTPFamily()) {
        resolver->reject(DOMException::create(SecurityError, "The URL protocol of the current origin is not supported: " + pageURL.protocol()));
        return promise;
    }

    KURL patternURL = executionContext->completeURL(options.scope());
    patternURL.removeFragmentIdentifier();
    if (!documentOrigin->canRequest(patternURL)) {
        resolver->reject(DOMException::create(SecurityError, "The scope must match the current origin."));
        return promise;
    }

    KURL scriptURL = executionContext->completeURL(url);
    scriptURL.removeFragmentIdentifier();
    if (!documentOrigin->canRequest(scriptURL)) {
        resolver->reject(DOMException::create(SecurityError, "The origin of the script must match the current origin."));
        return promise;
    }

    if (!patternURL.string().startsWith(scriptURL.baseAsString())) {
        resolver->reject(DOMException::create(SecurityError, "The scope must be under the directory of the script URL."));
        return promise;
    }

    m_provider->registerServiceWorker(patternURL, scriptURL, new CallbackPromiseAdapter<ServiceWorkerRegistration, ServiceWorkerError>(resolver));

    return promise;
}

class BooleanValue {
public:
    typedef bool WebType;
    static bool take(ScriptPromiseResolver* resolver, WebType* boolean)
    {
        return *boolean;
    }
    static void dispose(WebType* boolean) { }

private:
    BooleanValue();
};

ScriptPromise ServiceWorkerContainer::getRegistration(ScriptState* scriptState, const String& documentURL)
{
    ASSERT(RuntimeEnabledFeatures::serviceWorkerEnabled());
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    ScriptPromise promise = resolver->promise();

    // FIXME: This should use the container's execution context, not
    // the callers.
    ExecutionContext* executionContext = scriptState->executionContext();
    RefPtr<SecurityOrigin> documentOrigin = executionContext->securityOrigin();
    String errorMessage;
    if (!documentOrigin->canAccessFeatureRequiringSecureOrigin(errorMessage)) {
        resolver->reject(DOMException::create(NotSupportedError, errorMessage));
        return promise;
    }

    KURL pageURL = KURL(KURL(), documentOrigin->toString());
    if (!pageURL.protocolIsInHTTPFamily()) {
        resolver->reject(DOMException::create(SecurityError, "The URL protocol of the current origin is not supported: " + pageURL.protocol()));
        return promise;
    }

    KURL completedURL = executionContext->completeURL(documentURL);
    completedURL.removeFragmentIdentifier();
    if (!documentOrigin->canRequest(completedURL)) {
        resolver->reject(DOMException::create(SecurityError, "The documentURL must match the current origin."));
        return promise;
    }
    m_provider->getRegistration(completedURL, new GetRegistrationCallback(resolver));

    return promise;
}

ServiceWorkerContainer::ReadyProperty* ServiceWorkerContainer::createReadyProperty()
{
    return new ReadyProperty(executionContext(), this, ReadyProperty::Ready);
}

ScriptPromise ServiceWorkerContainer::ready(ScriptState* callerState)
{
    if (!executionContext())
        return ScriptPromise();

    if (!callerState->world().isMainWorld()) {
        // FIXME: Support .ready from isolated worlds when
        // ScriptPromiseProperty can vend Promises in isolated worlds.
        return ScriptPromise::rejectWithDOMException(callerState, DOMException::create(NotSupportedError, "'ready' is only supported in pages."));
    }

    return m_ready->promise(callerState->world());
}

// If the WebServiceWorker is up for adoption (does not have a
// WebServiceWorkerProxy owner), rejects the adoption by deleting the
// WebServiceWorker.
static void deleteIfNoExistingOwner(WebServiceWorker* serviceWorker)
{
    if (serviceWorker && !serviceWorker->proxy())
        delete serviceWorker;
}

void ServiceWorkerContainer::setController(WebServiceWorker* serviceWorker)
{
    if (!executionContext()) {
        deleteIfNoExistingOwner(serviceWorker);
        return;
    }
    m_controller = ServiceWorker::from(executionContext(), serviceWorker);
}

void ServiceWorkerContainer::setReadyRegistration(WebServiceWorkerRegistration* registration)
{
    if (!executionContext()) {
        ServiceWorkerRegistration::dispose(registration);
        return;
    }

    ServiceWorkerRegistration* readyRegistration = ServiceWorkerRegistration::from(executionContext(), registration);
    ASSERT(readyRegistration->active());

    if (m_readyRegistration) {
        ASSERT(m_readyRegistration == readyRegistration);
        ASSERT(m_ready->state() == ReadyProperty::Resolved);
        return;
    }

    m_readyRegistration = readyRegistration;
    m_ready->resolve(readyRegistration);
}

void ServiceWorkerContainer::dispatchMessageEvent(const WebString& message, const WebMessagePortChannelArray& webChannels)
{
    if (!executionContext() || !executionContext()->executingWindow())
        return;

    OwnPtrWillBeRawPtr<MessagePortArray> ports = MessagePort::toMessagePortArray(executionContext(), webChannels);
    RefPtr<SerializedScriptValue> value = SerializedScriptValue::createFromWire(message);
    executionContext()->executingWindow()->dispatchEvent(MessageEvent::create(ports.release(), value));
}

ServiceWorkerContainer::ServiceWorkerContainer(ExecutionContext* executionContext)
    : ContextLifecycleObserver(executionContext)
    , m_provider(0)
{

    if (!executionContext)
        return;

    m_ready = createReadyProperty();

    if (ServiceWorkerContainerClient* client = ServiceWorkerContainerClient::from(executionContext)) {
        m_provider = client->provider();
        if (m_provider)
            m_provider->setClient(this);
    }
}

} // namespace blink
<commit_msg>ServiceWorker: Add null check in ServiceWorkerContainer::getRegistration()<commit_after>/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "config.h"
#include "modules/serviceworkers/ServiceWorkerContainer.h"

#include "bindings/core/v8/CallbackPromiseAdapter.h"
#include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/SerializedScriptValue.h"
#include "core/dom/DOMException.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/ExecutionContext.h"
#include "core/dom/MessagePort.h"
#include "core/events/MessageEvent.h"
#include "core/frame/LocalDOMWindow.h"
#include "modules/serviceworkers/ServiceWorker.h"
#include "modules/serviceworkers/ServiceWorkerContainerClient.h"
#include "modules/serviceworkers/ServiceWorkerError.h"
#include "modules/serviceworkers/ServiceWorkerRegistration.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "public/platform/WebServiceWorker.h"
#include "public/platform/WebServiceWorkerProvider.h"
#include "public/platform/WebServiceWorkerRegistration.h"
#include "public/platform/WebString.h"
#include "public/platform/WebURL.h"

namespace blink {

// This wraps CallbackPromiseAdapter and resolves the promise with undefined
// when nullptr is given to onSuccess.
class GetRegistrationCallback : public WebServiceWorkerProvider::WebServiceWorkerGetRegistrationCallbacks {
public:
    explicit GetRegistrationCallback(PassRefPtr<ScriptPromiseResolver> resolver)
        : m_resolver(resolver)
        , m_adapter(m_resolver) { }
    virtual ~GetRegistrationCallback() { }
    virtual void onSuccess(WebServiceWorkerRegistration* registration) override
    {
        if (registration)
            m_adapter.onSuccess(registration);
        else if (m_resolver->executionContext() && !m_resolver->executionContext()->activeDOMObjectsAreStopped())
            m_resolver->resolve();
    }
    virtual void onError(WebServiceWorkerError* error) override { m_adapter.onError(error); }
private:
    RefPtr<ScriptPromiseResolver> m_resolver;
    CallbackPromiseAdapter<ServiceWorkerRegistration, ServiceWorkerError> m_adapter;
    WTF_MAKE_NONCOPYABLE(GetRegistrationCallback);
};

ServiceWorkerContainer* ServiceWorkerContainer::create(ExecutionContext* executionContext)
{
    return new ServiceWorkerContainer(executionContext);
}

ServiceWorkerContainer::~ServiceWorkerContainer()
{
    ASSERT(!m_provider);
}

void ServiceWorkerContainer::willBeDetachedFromFrame()
{
    if (m_provider) {
        m_provider->setClient(0);
        m_provider = nullptr;
    }
}

void ServiceWorkerContainer::trace(Visitor* visitor)
{
    visitor->trace(m_controller);
    visitor->trace(m_readyRegistration);
    visitor->trace(m_ready);
}

ScriptPromise ServiceWorkerContainer::registerServiceWorker(ScriptState* scriptState, const String& url, const RegistrationOptions& options)
{
    ASSERT(RuntimeEnabledFeatures::serviceWorkerEnabled());
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    ScriptPromise promise = resolver->promise();

    if (!m_provider) {
        resolver->reject(DOMException::create(InvalidStateError, "The document is in an invalid state."));
        return promise;
    }

    // FIXME: This should use the container's execution context, not
    // the callers.
    ExecutionContext* executionContext = scriptState->executionContext();
    RefPtr<SecurityOrigin> documentOrigin = executionContext->securityOrigin();
    String errorMessage;
    if (!documentOrigin->canAccessFeatureRequiringSecureOrigin(errorMessage)) {
        resolver->reject(DOMException::create(NotSupportedError, errorMessage));
        return promise;
    }

    KURL pageURL = KURL(KURL(), documentOrigin->toString());
    if (!pageURL.protocolIsInHTTPFamily()) {
        resolver->reject(DOMException::create(SecurityError, "The URL protocol of the current origin is not supported: " + pageURL.protocol()));
        return promise;
    }

    KURL patternURL = executionContext->completeURL(options.scope());
    patternURL.removeFragmentIdentifier();
    if (!documentOrigin->canRequest(patternURL)) {
        resolver->reject(DOMException::create(SecurityError, "The scope must match the current origin."));
        return promise;
    }

    KURL scriptURL = executionContext->completeURL(url);
    scriptURL.removeFragmentIdentifier();
    if (!documentOrigin->canRequest(scriptURL)) {
        resolver->reject(DOMException::create(SecurityError, "The origin of the script must match the current origin."));
        return promise;
    }

    if (!patternURL.string().startsWith(scriptURL.baseAsString())) {
        resolver->reject(DOMException::create(SecurityError, "The scope must be under the directory of the script URL."));
        return promise;
    }

    m_provider->registerServiceWorker(patternURL, scriptURL, new CallbackPromiseAdapter<ServiceWorkerRegistration, ServiceWorkerError>(resolver));

    return promise;
}

class BooleanValue {
public:
    typedef bool WebType;
    static bool take(ScriptPromiseResolver* resolver, WebType* boolean)
    {
        return *boolean;
    }
    static void dispose(WebType* boolean) { }

private:
    BooleanValue();
};

ScriptPromise ServiceWorkerContainer::getRegistration(ScriptState* scriptState, const String& documentURL)
{
    ASSERT(RuntimeEnabledFeatures::serviceWorkerEnabled());
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    ScriptPromise promise = resolver->promise();

    if (!m_provider) {
        resolver->reject(DOMException::create(InvalidStateError, "The document is in an invalid state."));
        return promise;
    }

    // FIXME: This should use the container's execution context, not
    // the callers.
    ExecutionContext* executionContext = scriptState->executionContext();
    RefPtr<SecurityOrigin> documentOrigin = executionContext->securityOrigin();
    String errorMessage;
    if (!documentOrigin->canAccessFeatureRequiringSecureOrigin(errorMessage)) {
        resolver->reject(DOMException::create(NotSupportedError, errorMessage));
        return promise;
    }

    KURL pageURL = KURL(KURL(), documentOrigin->toString());
    if (!pageURL.protocolIsInHTTPFamily()) {
        resolver->reject(DOMException::create(SecurityError, "The URL protocol of the current origin is not supported: " + pageURL.protocol()));
        return promise;
    }

    KURL completedURL = executionContext->completeURL(documentURL);
    completedURL.removeFragmentIdentifier();
    if (!documentOrigin->canRequest(completedURL)) {
        resolver->reject(DOMException::create(SecurityError, "The documentURL must match the current origin."));
        return promise;
    }
    m_provider->getRegistration(completedURL, new GetRegistrationCallback(resolver));

    return promise;
}

ServiceWorkerContainer::ReadyProperty* ServiceWorkerContainer::createReadyProperty()
{
    return new ReadyProperty(executionContext(), this, ReadyProperty::Ready);
}

ScriptPromise ServiceWorkerContainer::ready(ScriptState* callerState)
{
    if (!executionContext())
        return ScriptPromise();

    if (!callerState->world().isMainWorld()) {
        // FIXME: Support .ready from isolated worlds when
        // ScriptPromiseProperty can vend Promises in isolated worlds.
        return ScriptPromise::rejectWithDOMException(callerState, DOMException::create(NotSupportedError, "'ready' is only supported in pages."));
    }

    return m_ready->promise(callerState->world());
}

// If the WebServiceWorker is up for adoption (does not have a
// WebServiceWorkerProxy owner), rejects the adoption by deleting the
// WebServiceWorker.
static void deleteIfNoExistingOwner(WebServiceWorker* serviceWorker)
{
    if (serviceWorker && !serviceWorker->proxy())
        delete serviceWorker;
}

void ServiceWorkerContainer::setController(WebServiceWorker* serviceWorker)
{
    if (!executionContext()) {
        deleteIfNoExistingOwner(serviceWorker);
        return;
    }
    m_controller = ServiceWorker::from(executionContext(), serviceWorker);
}

void ServiceWorkerContainer::setReadyRegistration(WebServiceWorkerRegistration* registration)
{
    if (!executionContext()) {
        ServiceWorkerRegistration::dispose(registration);
        return;
    }

    ServiceWorkerRegistration* readyRegistration = ServiceWorkerRegistration::from(executionContext(), registration);
    ASSERT(readyRegistration->active());

    if (m_readyRegistration) {
        ASSERT(m_readyRegistration == readyRegistration);
        ASSERT(m_ready->state() == ReadyProperty::Resolved);
        return;
    }

    m_readyRegistration = readyRegistration;
    m_ready->resolve(readyRegistration);
}

void ServiceWorkerContainer::dispatchMessageEvent(const WebString& message, const WebMessagePortChannelArray& webChannels)
{
    if (!executionContext() || !executionContext()->executingWindow())
        return;

    OwnPtrWillBeRawPtr<MessagePortArray> ports = MessagePort::toMessagePortArray(executionContext(), webChannels);
    RefPtr<SerializedScriptValue> value = SerializedScriptValue::createFromWire(message);
    executionContext()->executingWindow()->dispatchEvent(MessageEvent::create(ports.release(), value));
}

ServiceWorkerContainer::ServiceWorkerContainer(ExecutionContext* executionContext)
    : ContextLifecycleObserver(executionContext)
    , m_provider(0)
{

    if (!executionContext)
        return;

    m_ready = createReadyProperty();

    if (ServiceWorkerContainerClient* client = ServiceWorkerContainerClient::from(executionContext)) {
        m_provider = client->provider();
        if (m_provider)
            m_provider->setClient(this);
    }
}

} // namespace blink
<|endoftext|>