<commit_before>/*
 * Copyright (C) 2009, 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 libport/path.cc
 ** \brief path: implements file libport/path.hh
 */

#include <iostream>
#include <libport/fcntl.h>
#include <libport/unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cctype>

#include <libport/contract.hh>
#include <libport/detect-win32.h>
#include <libport/finally.hh>
#include <libport/foreach.hh>
#include <libport/path.hh>
#include <libport/tokenizer.hh>

// Implementation detail: if path_ is empty and absolute_ is false,
// then the path is '.'

namespace libport
{
  path::path(const std::string& p)
  {
    init(p);
  }

  path::path(const char* p)
  {
    init(p);
  }

  void
  path::init(std::string p)
  {
    if (p.empty())
      throw invalid_path("Path can't be empty.");

    // Compute volume_ and absolute_.
#if defined WIN32
    // Under Win32, absolute paths start with a letter followed by
    // ":\". If the trailing slash is missing, this is a relative
    // path.
    if (2 <= p.length()
	&& isalpha(p[0]) && p[1] == ':')
    {
      volume_ = p.substr(0, 2);
      absolute_ = p.length() >= 3 && p[2] == '\\';
      p.erase(0, absolute_ ? 3 : 2);
    }
    // Network share, such as "\\shared volume\foo\bar"
    else if (3 <= p.length()
	     && p[0] == '\\' && p[1] == '\\')
    {
      absolute_ = true;
      std::string::size_type pos = p.find('\\', 3);
      if (pos == std::string::npos)
      {
	volume_ = p;
	p.clear();
      }
      else
      {
	volume_ = p.substr(0, pos);
	p = p.erase(0, pos);
      }
    }
    // Fallback to Unix cases for subsystems such as cygwin
    else
#endif // WIN32
    if (!p.empty() && p[0] == '/')
    {
      absolute_ = true;
      p = p.erase(0, 0);
    }
    else
      absolute_ = false;

    // Cut directories on / and \.
    foreach (const std::string& component, make_tokenizer(p, WIN32_IF("/\\", "/")))
      append_dir(component);
  }

  path&
  path::operator=(const path& rhs)
  {
    absolute_ = rhs.absolute_;
    path_ = rhs.path_;
#if defined WIN32
    volume_ = rhs.volume_;
#endif
    return *this;
  }

  path&
  path::operator/=(const path& rhs)
  {
    if (rhs.absolute_get())
      throw invalid_path(
        "Rhs of concatenation is absolute: " + rhs.to_string());
#ifdef WIN32
    if (!rhs.volume_.empty())
      throw invalid_path("concatenation of path with volume: " +
			 rhs.to_string());
#endif
    for (path_type::const_iterator dir = rhs.path_.begin();
	 dir != rhs.path_.end();
	 ++dir)
      append_dir(*dir);

    return *this;
  }

  path
  path::operator/(const path& rhs) const
  {
    path res = *this;
    return res /= rhs;
  }

  path::operator std::string() const
  {
    return to_string();
  }

  std::string
  path::to_string() const
  {
    if (!absolute_ && path_.empty())
      return ".";

    std::string res = WIN32_IF(volume_, "");
    if (absolute_)
      res += separator_;
    bool tail = false;
    foreach (const std::string& dir, path_)
    {
      if (tail++)
	res += separator_;
      res += dir;
    }
    return res;
  }

  bool
  path::operator==(const path& rhs) const
  {
    return (volume_get() == rhs.volume_get()
            && absolute_get() == rhs.absolute_get()
            && components() == rhs.components());
  }

  std::ostream&
  path::dump(std::ostream& o) const
  {
    return o << operator std::string();
  }

  void
  path::append_dir(const std::string& dir)
  {
    precondition(dir.find(separator_) == std::string::npos);

    if (!dir.empty() && dir != ".")
    {
      // The following does not work properly with symlinks.  One
      // cannot expect that removing "foo/../" inside a valid path
      // results in the same path.  We should check whether "foo" is
      // *not* a symlink before playing this kind of trick.
#if 0
      if (dir == ".."
          && !path_.empty() && *path_.rbegin() != "..")
        path_.pop_back();
      else
#endif
	path_.push_back(dir);
    }
  }

  std::string
  path::basename() const
  {
    // basename of / is /, basename of . is .
    if (path_.empty())
      return *this;

    return path_.back();
  }

  std::string
  path::extension() const
  {
    std::string name = basename();
    size_t pos = name.rfind(".");

    if (pos == std::string::npos || pos == name.size() - 1)
      return "";

    return name.substr(pos + 1);
  }

  path
  path::dirname() const
  {
    // dirname of / is /, dirname of . is .
    if (path_.empty())
      return *this;

    std::string last = path_.back();
    // The const cast here is justified since the modification is
    // systematically reverted
    const_cast<path*>(this)->path_.pop_back();
    libport::Finally finally(
      boost::bind(&path_type::push_back,
		  boost::ref(const_cast<path*>(this)->path_), last));
    path res = path_.empty() ? "." : *this;
    return res;
  }

  bool path::exists() const
  {
    struct stat buf;
    return 0 == stat(to_string().c_str(), &buf);
  }

  bool path::create() const
  {
    int fd = open(to_string().c_str(),
                  O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
    if (fd == -1)
      return false;
    close(fd);
    return true;
  }

  bool path::remove() const
  {
    return !unlink(to_string().c_str());
  }

  const path::path_type& path::components() const
  {
    return path_;
  }
}
<commit_msg>Path: do not forget to print the volume on WIN32.<commit_after>/*
 * Copyright (C) 2009, 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 libport/path.cc
 ** \brief path: implements file libport/path.hh
 */

#include <iostream>
#include <libport/fcntl.h>
#include <libport/unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cctype>

#include <libport/contract.hh>
#include <libport/detect-win32.h>
#include <libport/finally.hh>
#include <libport/foreach.hh>
#include <libport/path.hh>
#include <libport/tokenizer.hh>

// Implementation detail: if path_ is empty and absolute_ is false,
// then the path is '.'

namespace libport
{
  path::path(const std::string& p)
  {
    init(p);
  }

  path::path(const char* p)
  {
    init(p);
  }

  void
  path::init(std::string p)
  {
    if (p.empty())
      throw invalid_path("Path can't be empty.");

    // Compute volume_ and absolute_.
#if defined WIN32
    // Under Win32, absolute paths start with a letter followed by
    // ":\". If the trailing slash is missing, this is a relative
    // path.
    if (2 <= p.length()
	&& isalpha(p[0]) && p[1] == ':')
    {
      volume_ = p.substr(0, 2);
      absolute_ = p.length() >= 3 && p[2] == '\\';
      p.erase(0, absolute_ ? 3 : 2);
    }
    // Network share, such as "\\shared volume\foo\bar"
    else if (3 <= p.length()
	     && p[0] == '\\' && p[1] == '\\')
    {
      absolute_ = true;
      std::string::size_type pos = p.find('\\', 3);
      if (pos == std::string::npos)
      {
	volume_ = p;
	p.clear();
      }
      else
      {
	volume_ = p.substr(0, pos);
	p = p.erase(0, pos);
      }
    }
    // Fallback to Unix cases for subsystems such as cygwin
    else
#endif // WIN32
    if (!p.empty() && p[0] == '/')
    {
      absolute_ = true;
      p = p.erase(0, 0);
    }
    else
      absolute_ = false;

    // Cut directories on / and \.
    foreach (const std::string& component, make_tokenizer(p, WIN32_IF("/\\", "/")))
      append_dir(component);
  }

  path&
  path::operator=(const path& rhs)
  {
    absolute_ = rhs.absolute_;
    path_ = rhs.path_;
#if defined WIN32
    volume_ = rhs.volume_;
#endif
    return *this;
  }

  path&
  path::operator/=(const path& rhs)
  {
    if (rhs.absolute_get())
      throw invalid_path(
        "Rhs of concatenation is absolute: " + rhs.to_string());
#ifdef WIN32
    if (!rhs.volume_.empty())
      throw invalid_path("concatenation of path with volume: " +
			 rhs.to_string());
#endif
    for (path_type::const_iterator dir = rhs.path_.begin();
	 dir != rhs.path_.end();
	 ++dir)
      append_dir(*dir);

    return *this;
  }

  path
  path::operator/(const path& rhs) const
  {
    path res = *this;
    return res /= rhs;
  }

  path::operator std::string() const
  {
    return to_string();
  }

  std::string
  path::to_string() const
  {
    if (!absolute_ && path_.empty())
      return WIN32_IF(volume_.empty() ? "." : volume_, ".");

    std::string res = WIN32_IF(volume_, "");
    if (absolute_)
      res += separator_;
    bool tail = false;
    foreach (const std::string& dir, path_)
    {
      if (tail++)
	res += separator_;
      res += dir;
    }
    return res;
  }

  bool
  path::operator==(const path& rhs) const
  {
    return (volume_get() == rhs.volume_get()
            && absolute_get() == rhs.absolute_get()
            && components() == rhs.components());
  }

  std::ostream&
  path::dump(std::ostream& o) const
  {
    return o << operator std::string();
  }

  void
  path::append_dir(const std::string& dir)
  {
    precondition(dir.find(separator_) == std::string::npos);

    if (!dir.empty() && dir != ".")
    {
      // The following does not work properly with symlinks.  One
      // cannot expect that removing "foo/../" inside a valid path
      // results in the same path.  We should check whether "foo" is
      // *not* a symlink before playing this kind of trick.
#if 0
      if (dir == ".."
          && !path_.empty() && *path_.rbegin() != "..")
        path_.pop_back();
      else
#endif
	path_.push_back(dir);
    }
  }

  std::string
  path::basename() const
  {
    // basename of / is /, basename of . is .
    if (path_.empty())
      return *this;

    return path_.back();
  }

  std::string
  path::extension() const
  {
    std::string name = basename();
    size_t pos = name.rfind(".");

    if (pos == std::string::npos || pos == name.size() - 1)
      return "";

    return name.substr(pos + 1);
  }

  path
  path::dirname() const
  {
    // dirname of / is /, dirname of . is .
    if (path_.empty())
      return *this;

    std::string last = path_.back();
    // The const cast here is justified since the modification is
    // systematically reverted
    const_cast<path*>(this)->path_.pop_back();
    libport::Finally finally(
      boost::bind(&path_type::push_back,
		  boost::ref(const_cast<path*>(this)->path_), last));
    path res = path_.empty() ? "." : *this;
    return res;
  }

  bool path::exists() const
  {
    struct stat buf;
    return 0 == stat(to_string().c_str(), &buf);
  }

  bool path::create() const
  {
    int fd = open(to_string().c_str(),
                  O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
    if (fd == -1)
      return false;
    close(fd);
    return true;
  }

  bool path::remove() const
  {
    return !unlink(to_string().c_str());
  }

  const path::path_type& path::components() const
  {
    return path_;
  }
}
<|endoftext|>


<commit_before>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   JavascriptInstance.cpp
 *  @brief  Javascript script instance used wit EC_Script.
 */

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "JavascriptInstance.h"
#include "JavascriptModule.h"
#include "ScriptMetaTypeDefines.h"
#include "NaaliCoreTypeDefines.h"
#include "EC_Script.h"
#include "IModule.h"
#include "AssetAPI.h"
#include "IAssetProvider.h" //to check if the code was loaded from a local or remote storage

#include "LoggingFunctions.h"
DEFINE_POCO_LOGGING_FUNCTIONS("JavascriptInstance")

#include <QFile>

#include "MemoryLeakCheck.h"

JavascriptInstance::JavascriptInstance(const QString &fileName, JavascriptModule *module)
:engine_(0),
sourceFile(fileName),
module_(module),
evaluated(false)
{
    CreateEngine();
    Load();
}

JavascriptInstance::JavascriptInstance(ScriptAssetPtr scriptRef, JavascriptModule *module)
:engine_(0),
scriptRef_(scriptRef),
module_(module),
evaluated(false)
{
    CreateEngine();
    Load();
}

JavascriptInstance::~JavascriptInstance()
{
    DeleteEngine();
}

void JavascriptInstance::Load()
{
    if (!engine_)
        CreateEngine();

    // Can't specify both a file source and an Asset API source.
    assert(sourceFile.isEmpty() || scriptRef_.get() == 0);

    //determine based on code origin whether it can be trusted with system access or not
    if (scriptRef_.get())
    {
        AssetProviderPtr provider = scriptRef_.get()->GetAssetProvider();
        if (provider->Name() == "Local")
            trusted_ = true;
        else
            trusted_ = false;
    }

    if (sourceFile.length() > 0)
    {
        program_ = LoadScript(sourceFile);
        trusted_ = true; //this is a local file directly, right?
    }

    // Do we even have a script to execute?
    if (program_.isEmpty() && (!scriptRef_.get() || scriptRef_->scriptContent.isEmpty()))
    {
        LogError("JavascriptInstance::Load: No script content to load!");
        return;
    }

    QString scriptSourceFilename = (scriptRef_.get() ? scriptRef_->Name() : sourceFile);
    QString &scriptContent = (scriptRef_.get() ? scriptRef_->scriptContent : program_);

    QScriptSyntaxCheckResult syntaxResult = engine_->checkSyntax(scriptContent);
    if (syntaxResult.state() != QScriptSyntaxCheckResult::Valid)
    {
        LogError("Syntax error in script " + scriptSourceFilename.toStdString() + "," + QString::number(syntaxResult.errorLineNumber()).toStdString() +
            ": " + syntaxResult.errorMessage().toStdString());

        // Delete our loaded script content (if any exists).
        program_ == "";
    }
}

QString JavascriptInstance::LoadScript(const QString &fileName)
{
    QString filename = fileName.trimmed();

    // First check if the include was supposed to go through the Asset API.
    if (module_)
    {
        ScriptAssetPtr asset = boost::dynamic_pointer_cast<ScriptAsset>(module_->GetFramework()->Asset()->GetAsset(fileName));
        if (asset)
            return asset->scriptContent;
    }

    // Otherwise, treat fileName as a local file to load up.

    QFile scriptFile(filename);
    if (!scriptFile.open(QIODevice::ReadOnly))
    {
        LogError(("JavascriptInstance::LoadScript: Failed to load script from file " + filename + "!").toStdString());
        return "";
    }

    QString result = scriptFile.readAll();
    scriptFile.close();

    QString trimmedResult = result.trimmed();
    if (trimmedResult.isEmpty())
    {
        LogWarning(("JavascriptInstance::LoadScript: Warning Loaded script from file " + filename + ", but the content was empty.").toStdString());
        return "";
    }
    return result;
}

void JavascriptInstance::Unload()
{
    DeleteEngine();
}

void JavascriptInstance::Run()
{
    // Need to have either absolute file path source or an Asset API source.
    if (!scriptRef_.get() && program_.isEmpty())
    {
        LogError("JavascriptInstance::Run: Cannot run, no script reference loaded.");
        return;
    }

    // Can't specify both a file source and an Asset API source.
    assert(sourceFile.isEmpty() || scriptRef_.get() == 0);

    // If we've already evaluated this script once before, create a new script engine to run it again, or otherwise
    // the effects would stack (we'd possibly register into signals twice, or other odd side effects).
    // We never allow a script to be run twice in this kind of "stacking" manner.
    if (evaluated)
    {
        Unload();
        Load();
    }

    if (!engine_)
    {
        LogError("JavascriptInstance::Run: Cannot run, script engine not loaded.");
        return;
    }

    // If no script specified at all, we'll have to abort.
    if (!scriptRef_.get() && program_.isEmpty())
        return;

    QString scriptSourceFilename = (scriptRef_.get() ? scriptRef_->Name() : sourceFile);
    QString &scriptContent = (scriptRef_.get() ? scriptRef_->scriptContent : program_);

    included_files_.clear();
    QScriptValue result = engine_->evaluate(scriptContent, scriptSourceFilename);
    if (engine_->hasUncaughtException())
        LogError(result.toString().toStdString());

    evaluated = true;
}

void JavascriptInstance::RegisterService(QObject *serviceObject, const QString &name)
{
    if (!engine_)
    {
        LogError("JavascriptInstance::RegisterService: No Qt script engine created when trying to register service to js script instance.");
        return;
    }
    if (!serviceObject)
    {
        LogError("JavascriptInstance::RegisterService: Trying to pass a null service object pointer to RegisterService!");
        return;
    }

    QScriptValue scriptValue = engine_->newQObject(serviceObject);
    engine_->globalObject().setProperty(name, scriptValue);
}

void JavascriptInstance::IncludeFile(const QString &path)
{
    for (uint i = 0; i < included_files_.size(); ++i)
    {
        if (included_files_[i].toLower() == path.toLower())
        {
            LogDebug("JavascriptInstance::IncludeFile: Not including already included file " + path.toStdString());
            return;
        }
    }

    QString script = LoadScript(path);

    QScriptContext *context = engine_->currentContext();
    assert(context);
    if (!context)
    {
        LogError("JavascriptInstance::IncludeFile: QScriptEngine::currentContext() returned null!");
        return;
    }

    QScriptContext *parent = context->parentContext();
    if (!parent)
    {
        LogError("JavascriptInstance::IncludeFile: QScriptEngine::parentContext() returned null!");
        return;
    }

    context->setActivationObject(context->parentContext()->activationObject());
    context->setThisObject(context->parentContext()->thisObject());

    QScriptSyntaxCheckResult syntaxResult = engine_->checkSyntax(script);
    if(syntaxResult.state() != QScriptSyntaxCheckResult::Valid)
    {
        LogError("JavascriptInstance::IncludeFile: Syntax error in " + path.toStdString() + syntaxResult.errorMessage().toStdString()
            + " In line:" + QString::number(syntaxResult.errorLineNumber()).toStdString());
        return;
    }

    QScriptValue result = engine_->evaluate(script);

    included_files_.push_back(path);

    if (engine_->hasUncaughtException())
        LogError(result.toString().toStdString());
}

void JavascriptInstance::ImportExtension(const QString &scriptExtensionName)
{
    assert(engine_);
    if (!engine_)
    {
        LogWarning(("JavascriptInstance::ImportExtension(" + scriptExtensionName + ") failed, QScriptEngine==null!").toStdString());
        return;
    }

    if (!trusted_)
    {
        LogWarning("JavascriptInstance::ImportExtension: refusing to load a QtScript plugin for an untrusted instance.");
        return;
    }

    QScriptValue success = engine_->importExtension(scriptExtensionName);
    if (!success.isUndefined()) // Yes, importExtension returns undefinedValue if the import succeeds. http://doc.qt.nokia.com/4.7/qscriptengine.html#importExtension
        LogWarning(std::string("JavascriptInstance::ImportExtension: Failed to load ") + scriptExtensionName.toStdString() + " plugin for QtScript!");
}

void JavascriptInstance::CreateEngine()
{
    if (engine_)
        DeleteEngine();
    engine_ = new QScriptEngine;
    connect(engine_, SIGNAL(signalHandlerException(const QScriptValue &)), SLOT(OnSignalHandlerException(const QScriptValue &)));

    ExposeQtMetaTypes(engine_);
    ExposeNaaliCoreTypes(engine_);
    ExposeCoreApiMetaTypes(engine_);

    EC_Script *ec = dynamic_cast<EC_Script *>(owner_.lock().get());
    module_->PrepareScriptInstance(this, ec);
    evaluated = false;
}

void JavascriptInstance::DeleteEngine()
{
    if (!engine_)
        return;

    program_ = "";
    engine_->abortEvaluation();

    // As a convention, we call a function 'OnScriptDestroyed' for each JS script
    // so that they can clean up their data before the script is removed from the object,
    // or when the system is unloading.

    QScriptValue destructor = engine_->globalObject().property("OnScriptDestroyed");
    if (!destructor.isUndefined())
        destructor.call();
    SAFE_DELETE(engine_);
}

void JavascriptInstance::OnSignalHandlerException(const QScriptValue& exception)
{
    LogError(exception.toString().toStdString());
}

<commit_msg>js sandbox new approach: instead of denying ImportExtension alltogther, remove blacklisted qt types from the namespace after import. Tested now with QDir, works.<commit_after>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   JavascriptInstance.cpp
 *  @brief  Javascript script instance used wit EC_Script.
 */

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "JavascriptInstance.h"
#include "JavascriptModule.h"
#include "ScriptMetaTypeDefines.h"
#include "NaaliCoreTypeDefines.h"
#include "EC_Script.h"
#include "IModule.h"
#include "AssetAPI.h"
#include "IAssetProvider.h" //to check if the code was loaded from a local or remote storage

#include "LoggingFunctions.h"
DEFINE_POCO_LOGGING_FUNCTIONS("JavascriptInstance")

#include <QFile>

#include "MemoryLeakCheck.h"

JavascriptInstance::JavascriptInstance(const QString &fileName, JavascriptModule *module)
:engine_(0),
sourceFile(fileName),
module_(module),
evaluated(false)
{
    CreateEngine();
    Load();
}

JavascriptInstance::JavascriptInstance(ScriptAssetPtr scriptRef, JavascriptModule *module)
:engine_(0),
scriptRef_(scriptRef),
module_(module),
evaluated(false)
{
    CreateEngine();
    Load();
}

JavascriptInstance::~JavascriptInstance()
{
    DeleteEngine();
}

void JavascriptInstance::Load()
{
    if (!engine_)
        CreateEngine();

    // Can't specify both a file source and an Asset API source.
    assert(sourceFile.isEmpty() || scriptRef_.get() == 0);

    //determine based on code origin whether it can be trusted with system access or not
    if (scriptRef_.get())
    {
        AssetProviderPtr provider = scriptRef_.get()->GetAssetProvider();
        if (provider->Name() == "Local")
            trusted_ = true;
        else
            trusted_ = false;
    }

    if (sourceFile.length() > 0)
    {
        program_ = LoadScript(sourceFile);
        trusted_ = true; //this is a local file directly, right?
    }

    // Do we even have a script to execute?
    if (program_.isEmpty() && (!scriptRef_.get() || scriptRef_->scriptContent.isEmpty()))
    {
        LogError("JavascriptInstance::Load: No script content to load!");
        return;
    }

    QString scriptSourceFilename = (scriptRef_.get() ? scriptRef_->Name() : sourceFile);
    QString &scriptContent = (scriptRef_.get() ? scriptRef_->scriptContent : program_);

    QScriptSyntaxCheckResult syntaxResult = engine_->checkSyntax(scriptContent);
    if (syntaxResult.state() != QScriptSyntaxCheckResult::Valid)
    {
        LogError("Syntax error in script " + scriptSourceFilename.toStdString() + "," + QString::number(syntaxResult.errorLineNumber()).toStdString() +
            ": " + syntaxResult.errorMessage().toStdString());

        // Delete our loaded script content (if any exists).
        program_ == "";
    }
}

QString JavascriptInstance::LoadScript(const QString &fileName)
{
    QString filename = fileName.trimmed();

    // First check if the include was supposed to go through the Asset API.
    if (module_)
    {
        ScriptAssetPtr asset = boost::dynamic_pointer_cast<ScriptAsset>(module_->GetFramework()->Asset()->GetAsset(fileName));
        if (asset)
            return asset->scriptContent;
    }

    // Otherwise, treat fileName as a local file to load up.

    QFile scriptFile(filename);
    if (!scriptFile.open(QIODevice::ReadOnly))
    {
        LogError(("JavascriptInstance::LoadScript: Failed to load script from file " + filename + "!").toStdString());
        return "";
    }

    QString result = scriptFile.readAll();
    scriptFile.close();

    QString trimmedResult = result.trimmed();
    if (trimmedResult.isEmpty())
    {
        LogWarning(("JavascriptInstance::LoadScript: Warning Loaded script from file " + filename + ", but the content was empty.").toStdString());
        return "";
    }
    return result;
}

void JavascriptInstance::Unload()
{
    DeleteEngine();
}

void JavascriptInstance::Run()
{
    // Need to have either absolute file path source or an Asset API source.
    if (!scriptRef_.get() && program_.isEmpty())
    {
        LogError("JavascriptInstance::Run: Cannot run, no script reference loaded.");
        return;
    }

    // Can't specify both a file source and an Asset API source.
    assert(sourceFile.isEmpty() || scriptRef_.get() == 0);

    // If we've already evaluated this script once before, create a new script engine to run it again, or otherwise
    // the effects would stack (we'd possibly register into signals twice, or other odd side effects).
    // We never allow a script to be run twice in this kind of "stacking" manner.
    if (evaluated)
    {
        Unload();
        Load();
    }

    if (!engine_)
    {
        LogError("JavascriptInstance::Run: Cannot run, script engine not loaded.");
        return;
    }

    // If no script specified at all, we'll have to abort.
    if (!scriptRef_.get() && program_.isEmpty())
        return;

    QString scriptSourceFilename = (scriptRef_.get() ? scriptRef_->Name() : sourceFile);
    QString &scriptContent = (scriptRef_.get() ? scriptRef_->scriptContent : program_);

    included_files_.clear();
    QScriptValue result = engine_->evaluate(scriptContent, scriptSourceFilename);
    if (engine_->hasUncaughtException())
        LogError(result.toString().toStdString());

    evaluated = true;
}

void JavascriptInstance::RegisterService(QObject *serviceObject, const QString &name)
{
    if (!engine_)
    {
        LogError("JavascriptInstance::RegisterService: No Qt script engine created when trying to register service to js script instance.");
        return;
    }
    if (!serviceObject)
    {
        LogError("JavascriptInstance::RegisterService: Trying to pass a null service object pointer to RegisterService!");
        return;
    }

    QScriptValue scriptValue = engine_->newQObject(serviceObject);
    engine_->globalObject().setProperty(name, scriptValue);
}

void JavascriptInstance::IncludeFile(const QString &path)
{
    for (uint i = 0; i < included_files_.size(); ++i)
    {
        if (included_files_[i].toLower() == path.toLower())
        {
            LogDebug("JavascriptInstance::IncludeFile: Not including already included file " + path.toStdString());
            return;
        }
    }

    QString script = LoadScript(path);

    QScriptContext *context = engine_->currentContext();
    assert(context);
    if (!context)
    {
        LogError("JavascriptInstance::IncludeFile: QScriptEngine::currentContext() returned null!");
        return;
    }

    QScriptContext *parent = context->parentContext();
    if (!parent)
    {
        LogError("JavascriptInstance::IncludeFile: QScriptEngine::parentContext() returned null!");
        return;
    }

    context->setActivationObject(context->parentContext()->activationObject());
    context->setThisObject(context->parentContext()->thisObject());

    QScriptSyntaxCheckResult syntaxResult = engine_->checkSyntax(script);
    if(syntaxResult.state() != QScriptSyntaxCheckResult::Valid)
    {
        LogError("JavascriptInstance::IncludeFile: Syntax error in " + path.toStdString() + syntaxResult.errorMessage().toStdString()
            + " In line:" + QString::number(syntaxResult.errorLineNumber()).toStdString());
        return;
    }

    QScriptValue result = engine_->evaluate(script);

    included_files_.push_back(path);

    if (engine_->hasUncaughtException())
        LogError(result.toString().toStdString());
}

void JavascriptInstance::ImportExtension(const QString &scriptExtensionName)
{
    assert(engine_);
    if (!engine_)
    {
        LogWarning(("JavascriptInstance::ImportExtension(" + scriptExtensionName + ") failed, QScriptEngine==null!").toStdString());
        return;
    }

    QScriptValue success = engine_->importExtension(scriptExtensionName);
    if (!success.isUndefined()) // Yes, importExtension returns undefinedValue if the import succeeds. http://doc.qt.nokia.com/4.7/qscriptengine.html#importExtension
        LogWarning(std::string("JavascriptInstance::ImportExtension: Failed to load ") + scriptExtensionName.toStdString() + " plugin for QtScript!");

    if (!trusted_)
    {
        QScriptValue exposed;
        exposed = engine_->globalObject().property("QDir");
        if (exposed.isValid())
        {
          engine_->globalObject().setProperty("QDir", QScriptValue::QScriptValue()); //passing an invalid val removes the property, http://doc.qt.nokia.com/4.6/qscriptvalue.html#setProperty
          LogInfo("JavascriptInstance::ImportExtension: removed QDir from the untrusted context.");
        }
    }
}

void JavascriptInstance::CreateEngine()
{
    if (engine_)
        DeleteEngine();
    engine_ = new QScriptEngine;
    connect(engine_, SIGNAL(signalHandlerException(const QScriptValue &)), SLOT(OnSignalHandlerException(const QScriptValue &)));

    ExposeQtMetaTypes(engine_);
    ExposeNaaliCoreTypes(engine_);
    ExposeCoreApiMetaTypes(engine_);

    EC_Script *ec = dynamic_cast<EC_Script *>(owner_.lock().get());
    module_->PrepareScriptInstance(this, ec);
    evaluated = false;
}

void JavascriptInstance::DeleteEngine()
{
    if (!engine_)
        return;

    program_ = "";
    engine_->abortEvaluation();

    // As a convention, we call a function 'OnScriptDestroyed' for each JS script
    // so that they can clean up their data before the script is removed from the object,
    // or when the system is unloading.

    QScriptValue destructor = engine_->globalObject().property("OnScriptDestroyed");
    if (!destructor.isUndefined())
        destructor.call();
    SAFE_DELETE(engine_);
}

void JavascriptInstance::OnSignalHandlerException(const QScriptValue& exception)
{
    LogError(exception.toString().toStdString());
}

<|endoftext|>


<commit_before>#include "player.h"
#include "ui_player.h"
#include "controller/commandcontroller.h"
#include "controller/selectioncontroller.h"
#include "geomObject/annotationgraphicsitemfactory.h"
#include "plugins/pluginloader.h"
#include <AnnotatorLib/Algo/InterpolateAnnotation.h>
#include <AnnotatorLib/Commands/NewAnnotation.h>
#include <AnnotatorLib/Commands/UpdateAnnotation.h>
#include <AnnotatorLib/Frame.h>
#include <QDebug>
#include <QFile>
#include <QMessageBox>
#include <geomObject/annotationgraphicsitem.h>

Player::Player(QWidget *parent) : QWidget(parent), ui(new Ui::Player) {
  ui->setupUi(this);
  videoplayer = new Videoplayer(); // Creating an instance of class videoplayer

  ui->btnNext->setAutoRepeat(true);
  ui->btnPrev->setAutoRepeat(true);

  videoplayer->setDelay(ui->speedSpinBox->value()); // get default value

  updateStatus(false); // set Status disable
  updateBtn();         // update the button Play & Pause

  connect(videoplayer, SIGNAL(showFrame(cv::Mat)), this,
          SLOT(showFrame(cv::Mat)));
  connect(videoplayer, SIGNAL(updateFrame(long)), this,
          SLOT(updateFrame(long)));
  connect(ui->horizontalSlider, SIGNAL(sendClickPosition(int)), this,
          SLOT(setSliderValue(int)));
  connect(videoplayer, SIGNAL(updateBtn()), this, SLOT(updateBtn()));
  connect(videoplayer, SIGNAL(sleep(int)), this, SLOT(sleep(int)));
  connect(videoplayer, SIGNAL(updateHorizontalSlider()), this,
          SLOT(updateHorizontalSlider()));
  connect(videoplayer, SIGNAL(setInputCoordinate(QPoint)), this,
          SLOT(setInputCoordinate(QPoint)));
  // command controller
  connect(CommandController::instance(), SIGNAL(signal_requestFrameRedraw()),
          this, SLOT(reload()));

  // create graphicsview to be able to draw objects on screen.
  scene = new OwnGraphicScene();
  overlay = new OwnGraphicView(scene, this);
  // overlay->setEnabled(false);
  ui->playerLayout->addWidget(overlay);
  overlay->show();

  connect(scene, SIGNAL(on_btnPause_clicked()), this,
          SLOT(on_btnPause_clicked()));

  connect(
      this, SIGNAL(signal_objectSelection(shared_ptr<AnnotatorLib::Object>)),
      scene, SLOT(on_signal_objectSelection(shared_ptr<AnnotatorLib::Object>)));
}

Player::~Player() {
  clearAnnotationsGraphics();
  delete videoplayer;
  delete scene;
  delete ui;
}

/**
 * setInputCoordinate	-	set image/video coordinate into scene to adjust
 * the coordinate system.
 */
void Player::setInputCoordinate(QPoint point) {
  scene->inputCoordinate = point;
}

void Player::setRateLabel(QLabel *label) { this->rateLabel = label; }

QString Player::getRateValue() {
  return "FPS: " + QString::number(videoplayer->rate);
}

std::shared_ptr<AnnotatorLib::Session> Player::getSession() { return this->session; }

void Player::closeProject() {
  this->currentFrame = cv::Mat();
  setProject(nullptr);
  this->videoplayer->close();
  scene->setSession(nullptr);
  updateStatus(false);           //disable ui
}

void Player::setProject(std::shared_ptr<AnnotatorLib::Project> project) {
  this->project = project;

  this->session = project ? project->getSession() : nullptr;

  ui->horizontalSlider->setMaximum(project ? project->getImageSet()->size() : 0);

  videoplayer->setImageSet(project ? project->getImageSet() : nullptr);
  ui->horizontalSlider->setMaximum(project ? project->getImageSet()->size() : 0);

  cv::Mat firstImage = project ? project->getImageSet()->next() : cv::Mat();
  scene->setSceneRect(0, 0, firstImage.cols, firstImage.rows);
  scene->setSession(project ? session : nullptr);

  this->setEnabled(project.get() != nullptr);

  if (project) {
    overlay->fitInView(scene->sceneRect());
    project->getImageSet()->gotoPosition(0);
  }

  updateStatus(true);
  updateBtn();
  updateTimeLabel();
}

void Player::loadVideo(QString fileName) {
  if (!fileName.isEmpty()) {
    if (LoadFile(fileName)) {
      updateStatus(true);
      updateBtn();
      setEnabled(true);
    }
  }
}

void Player::clearAnnotationsGraphics() {
  while (!annotationGraphics.empty()) {
    delete annotationGraphics.front();
    annotationGraphics.pop_front();
  }
  scene->update();
}

/**
 * LoadFile	-	Open and load a video
 *
 * @param fileName	-	file Path
 *
 * @return true if the file is successfully loaded
 */
bool Player::LoadFile(const QString &fileName) {
  QFile file(fileName);
  if (!file.open(QFile::ReadOnly)) {
    QMessageBox::warning(this, tr("VideoPlayer"),
                         tr("Unable to load file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
    return false;
  }

  // change the cursor
  QApplication::setOverrideCursor(Qt::WaitCursor);

  // input file
  if (!videoplayer->setInput(fileName.toStdString())) {
    QMessageBox::warning(this, tr("VideoPlayer"),
                         tr("Unable to load file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
    return false;
  }

  // restore the cursor
  QApplication::restoreOverrideCursor();

  // update the time label
  updateTimeLabel();

  return true;
}

/**
 * updateStatus	-	Update the enabled property of menu
 *
 * @param var	-	the enable variable
 */
void Player::updateStatus(bool enable) {
  ui->horizontalSlider->setEnabled(enable);
  ui->btnPrev->setEnabled(enable);
  ui->btnNext->setEnabled(enable);
  ui->btnPlay->setEnabled(enable);
  ui->btnStop->setEnabled(enable);
  ui->btnPause->setEnabled(enable);

  if (!enable) {
    ui->horizontalSlider->setValue(0);
  }
}

/**get()
 * updateBtn	-	update the button Play & Pause
 *
 */
void Player::updateBtn() {
  bool isStop = videoplayer->isStop();
  ui->btnPause->setVisible(!isStop);
  ui->btnPlay->setVisible(isStop);
}

/**
 * showFrame	-	show a frame
 *
 * @param image	-	the image to be showed
 *
 */
void Player::showFrame(cv::Mat frame) {
  currentFrame = frame;
  cv::Mat tmp;

  cv::Size size;
  size.width = scene->sceneRect().width();
  size.height = scene->sceneRect().height();

  tmp.convertTo(tmp, CV_8U);
  cv::resize(currentFrame, tmp, size);
  cvtColor(currentFrame, tmp, CV_BGR2RGB);

  QImage img = QImage((const unsigned char *)(tmp.data), tmp.cols, tmp.rows,
                      tmp.step, QImage::Format_RGB888);

  scene->setSceneRect(img.rect());
  overlay->fitInView(img.rect());
  QPixmap pim = QPixmap::fromImage(img);
  scene->setBackgroundBrush(pim);
}

void Player::updateFrame(long frame_nmb) {
  shared_ptr<AnnotatorLib::Frame> f = session->getFrame(frame_nmb);
  if (!f)
    f = std::make_shared<AnnotatorLib::Frame>(
        frame_nmb); // create temporary frame

  if (autoAnnotation && SelectionController::instance()->getSelectedObject()) {
    Annotator::Plugin *plugin =
        Annotator::PluginLoader::getInstance().getCurrent();

    if (plugin) {
//      shared_ptr<AnnotatorLib::Annotation> previousA = nullptr;
//      shared_ptr<AnnotatorLib::Annotation> nextA = nullptr;
//      SelectionController::instance()
//          ->getSelectedObject()
//          ->findClosestKeyFrames(f, previousA, nextA);
//      if (previousA !=
//          SelectionController::instance()
//              ->getSelectedObject()
//              ->getLastAnnotation())
        for (shared_ptr<AnnotatorLib::Commands::Command> command :
             plugin->calculate(SelectionController::instance()->getSelectedObject(), f, false)) {
          CommandController::instance()->execute(command);
        }
    }
  }

  this->scene->setCurrentFrame(frame_nmb);
  showAnnotationsOfFrame(f);
  this->scene->update();
}

void Player::showAnnotationsOfFrame(shared_ptr<AnnotatorLib::Frame> frame) {
  clearAnnotationsGraphics();

  for (shared_ptr<AnnotatorLib::Annotation> annotation :
       AnnotatorLib::Algo::InterpolateAnnotation::getInterpolations(
           this->session, frame)) {

    AnnotationGraphicsItem *graphicsItem =
        AnnotationGraphicsItemFactory::createItem(annotation);

    connect(SelectionController::instance(),
            SIGNAL(signal_objectSelection(shared_ptr<AnnotatorLib::Object>)),
            graphicsItem,
            SLOT(on_objectSelected(shared_ptr<AnnotatorLib::Object>)));

    graphicsItem->setPlayer(this);
    scene->addItem(graphicsItem);
    annotationGraphics.push_back(graphicsItem);
  }

//  // if nothing is selected take first annotation
//  if (!SelectionController::instance()->getSelectedObject()) {
//    if (annotationGraphics.empty()) {
//      SelectionController::instance()->setSelectedObject(nullptr);
//    }
//  }
}

/**
 * updateHorizontalSlider	-	update the progress bar
 *
 */
void Player::updateHorizontalSlider() {
  // update the progress bar
  ui->horizontalSlider->setValue(videoplayer->getCurFrameNr());
  updateTimeLabel();
}

void Player::on_horizontalSlider_sliderMoved(int newpos) {
  long pos =
      newpos * videoplayer->getTotalFrameNr() / ui->horizontalSlider->maximum();
  on_frameSelected(pos);
}

/**
 * setSliderValue	-	set new value on the progress bar
 *
*/
void Player::setSliderValue(int newpos) {
  ui->horizontalSlider->setValue(newpos);
  on_horizontalSlider_sliderMoved(newpos);
}

void Player::on_frameSelected(long index) {
  this->videoplayer->on_frameSelected(index - 1); // why -1?
  updateTimeLabel();
  updateHorizontalSlider();
}

/**
 * updateTimeLabel	-	update Time Label
 */
void Player::updateTimeLabel() {

  double pos_ms = 0;
  double length_ms = 0;
  long cfn = 0;
  long tfn = 0;
  if (this->videoplayer->isOpened()) {
    pos_ms = videoplayer->getPositionMS();
    length_ms = videoplayer->getLengthMS();
    cfn = videoplayer->getCurFrameNr();
    tfn = videoplayer->getTotalFrameNr();
  }
  QString curPos =
      QDateTime::fromMSecsSinceEpoch(pos_ms - 3600000)
          .toString("hh:mm:ss");

  QString length =
      QDateTime::fromMSecsSinceEpoch(length_ms - 3600000)
          .toString("hh:mm:ss");

  ui->timeLabel->setText(tr(""
                            "%1 / %2")
                             .arg(curPos, length));

  ui->frameNrLabel->setText(
      tr(""
         "%1 / %2")
          .arg(QString::number(cfn), QString::number(tfn)));
}

/**
 * play	-	play the video
 *
 */
void Player::play() {
  // video->setDelay(1000.f / video->getFrameRate());
  videoplayer->playIt();
}

/**
 * pause	-	pause the video
 *
 */
void Player::pause() { videoplayer->pauseIt(); }

/**
 * sleep	-	pause the video for several msecs
 *
 * @param msecs
 */
void Player::sleep(int msecs) { videoplayer->wait(msecs); }

///#################################################################################################///

void Player::reload() {
  this->videoplayer->reload();
  // TODO: reload annotations?
}

void Player::enableDrawing(bool enable)
{
  this->ui->scrollArea->setEnabled(enable);
}

/**
 * update the video speed by a factor f in percent
 *
 */
void Player::on_speedSpinBox_valueChanged(int f) {
  // TODO: set proper framerate
  videoplayer->setDelay((100.f * videoplayer->getFrameRate()) / (float)f);
}

///#########################################SLOTS###########################################///

void Player::on_btnPlay_clicked() { play(); }

void Player::on_btnPause_clicked() { pause(); }

void Player::on_btnStop_clicked() { videoplayer->stopIt(); }

void Player::on_btnPrev_clicked() {
  // this->setAutoAnnotation(false);
  videoplayer->prevFrame();
}

void Player::on_btnNext_clicked() { videoplayer->nextFrame(); }

void Player::on_autoAnnotate(bool enabled) {
  if (enabled)
    this->ui->speedSpinBox->setValue(100);
  else
    this->ui->speedSpinBox->setValue(50);
  this->autoAnnotation = enabled;
}
<commit_msg>disable prevBtn and trackbar while using plugins<commit_after>#include "player.h"
#include "ui_player.h"
#include "controller/commandcontroller.h"
#include "controller/selectioncontroller.h"
#include "geomObject/annotationgraphicsitemfactory.h"
#include "plugins/pluginloader.h"
#include <AnnotatorLib/Algo/InterpolateAnnotation.h>
#include <AnnotatorLib/Commands/NewAnnotation.h>
#include <AnnotatorLib/Commands/UpdateAnnotation.h>
#include <AnnotatorLib/Frame.h>
#include <QDebug>
#include <QFile>
#include <QMessageBox>
#include <geomObject/annotationgraphicsitem.h>

Player::Player(QWidget *parent) : QWidget(parent), ui(new Ui::Player) {
  ui->setupUi(this);
  videoplayer = new Videoplayer(); // Creating an instance of class videoplayer

  ui->btnNext->setAutoRepeat(true);
  ui->btnPrev->setAutoRepeat(true);

  videoplayer->setDelay(ui->speedSpinBox->value()); // get default value

  updateStatus(false); // set Status disable
  updateBtn();         // update the button Play & Pause

  connect(videoplayer, SIGNAL(showFrame(cv::Mat)), this,
          SLOT(showFrame(cv::Mat)));
  connect(videoplayer, SIGNAL(updateFrame(long)), this,
          SLOT(updateFrame(long)));
  connect(ui->horizontalSlider, SIGNAL(sendClickPosition(int)), this,
          SLOT(setSliderValue(int)));
  connect(videoplayer, SIGNAL(updateBtn()), this, SLOT(updateBtn()));
  connect(videoplayer, SIGNAL(sleep(int)), this, SLOT(sleep(int)));
  connect(videoplayer, SIGNAL(updateHorizontalSlider()), this,
          SLOT(updateHorizontalSlider()));
  connect(videoplayer, SIGNAL(setInputCoordinate(QPoint)), this,
          SLOT(setInputCoordinate(QPoint)));
  // command controller
  connect(CommandController::instance(), SIGNAL(signal_requestFrameRedraw()),
          this, SLOT(reload()));

  // create graphicsview to be able to draw objects on screen.
  scene = new OwnGraphicScene();
  overlay = new OwnGraphicView(scene, this);
  // overlay->setEnabled(false);
  ui->playerLayout->addWidget(overlay);
  overlay->show();

  connect(scene, SIGNAL(on_btnPause_clicked()), this,
          SLOT(on_btnPause_clicked()));

  connect(
      this, SIGNAL(signal_objectSelection(shared_ptr<AnnotatorLib::Object>)),
      scene, SLOT(on_signal_objectSelection(shared_ptr<AnnotatorLib::Object>)));
}

Player::~Player() {
  clearAnnotationsGraphics();
  delete videoplayer;
  delete scene;
  delete ui;
}

/**
 * setInputCoordinate	-	set image/video coordinate into scene to adjust
 * the coordinate system.
 */
void Player::setInputCoordinate(QPoint point) {
  scene->inputCoordinate = point;
}

void Player::setRateLabel(QLabel *label) { this->rateLabel = label; }

QString Player::getRateValue() {
  return "FPS: " + QString::number(videoplayer->rate);
}

std::shared_ptr<AnnotatorLib::Session> Player::getSession() { return this->session; }

void Player::closeProject() {
  this->currentFrame = cv::Mat();
  setProject(nullptr);
  this->videoplayer->close();
  scene->setSession(nullptr);
  updateStatus(false);           //disable ui
}

void Player::setProject(std::shared_ptr<AnnotatorLib::Project> project) {
  this->project = project;

  this->session = project ? project->getSession() : nullptr;

  ui->horizontalSlider->setMaximum(project ? project->getImageSet()->size() : 0);

  videoplayer->setImageSet(project ? project->getImageSet() : nullptr);
  ui->horizontalSlider->setMaximum(project ? project->getImageSet()->size() : 0);

  cv::Mat firstImage = project ? project->getImageSet()->next() : cv::Mat();
  scene->setSceneRect(0, 0, firstImage.cols, firstImage.rows);
  scene->setSession(project ? session : nullptr);

  this->setEnabled(project.get() != nullptr);

  if (project) {
    overlay->fitInView(scene->sceneRect());
    project->getImageSet()->gotoPosition(0);
  }

  updateStatus(true);
  updateBtn();
  updateTimeLabel();
}

void Player::loadVideo(QString fileName) {
  if (!fileName.isEmpty()) {
    if (LoadFile(fileName)) {
      updateStatus(true);
      updateBtn();
      setEnabled(true);
    }
  }
}

void Player::clearAnnotationsGraphics() {
  while (!annotationGraphics.empty()) {
    delete annotationGraphics.front();
    annotationGraphics.pop_front();
  }
  scene->update();
}

/**
 * LoadFile	-	Open and load a video
 *
 * @param fileName	-	file Path
 *
 * @return true if the file is successfully loaded
 */
bool Player::LoadFile(const QString &fileName) {
  QFile file(fileName);
  if (!file.open(QFile::ReadOnly)) {
    QMessageBox::warning(this, tr("VideoPlayer"),
                         tr("Unable to load file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
    return false;
  }

  // change the cursor
  QApplication::setOverrideCursor(Qt::WaitCursor);

  // input file
  if (!videoplayer->setInput(fileName.toStdString())) {
    QMessageBox::warning(this, tr("VideoPlayer"),
                         tr("Unable to load file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
    return false;
  }

  // restore the cursor
  QApplication::restoreOverrideCursor();

  // update the time label
  updateTimeLabel();

  return true;
}

/**
 * updateStatus	-	Update the enabled property of menu
 *
 * @param var	-	the enable variable
 */
void Player::updateStatus(bool enable) {
  ui->horizontalSlider->setEnabled(enable);
  ui->btnPrev->setEnabled(enable);
  ui->btnNext->setEnabled(enable);
  ui->btnPlay->setEnabled(enable);
  ui->btnStop->setEnabled(enable);
  ui->btnPause->setEnabled(enable);

  if (!enable) {
    ui->horizontalSlider->setValue(0);
  }
}

/**get()
 * updateBtn	-	update the button Play & Pause
 *
 */
void Player::updateBtn() {
  bool isStop = videoplayer->isStop();
  ui->btnPause->setVisible(!isStop);
  ui->btnPlay->setVisible(isStop);
}

/**
 * showFrame	-	show a frame
 *
 * @param image	-	the image to be showed
 *
 */
void Player::showFrame(cv::Mat frame) {
  currentFrame = frame;
  cv::Mat tmp;

  cv::Size size;
  size.width = scene->sceneRect().width();
  size.height = scene->sceneRect().height();

  tmp.convertTo(tmp, CV_8U);
  cv::resize(currentFrame, tmp, size);
  cvtColor(currentFrame, tmp, CV_BGR2RGB);

  QImage img = QImage((const unsigned char *)(tmp.data), tmp.cols, tmp.rows,
                      tmp.step, QImage::Format_RGB888);

  scene->setSceneRect(img.rect());
  overlay->fitInView(img.rect());
  QPixmap pim = QPixmap::fromImage(img);
  scene->setBackgroundBrush(pim);
}

void Player::updateFrame(long frame_nmb) {
  shared_ptr<AnnotatorLib::Frame> f = session->getFrame(frame_nmb);
  if (!f)
    f = std::make_shared<AnnotatorLib::Frame>(
        frame_nmb); // create temporary frame

  if (autoAnnotation && SelectionController::instance()->getSelectedObject()) {
    Annotator::Plugin *plugin =
        Annotator::PluginLoader::getInstance().getCurrent();

    if (plugin) {
        for (shared_ptr<AnnotatorLib::Commands::Command> command :
             plugin->calculate(SelectionController::instance()->getSelectedObject(), f, false)) {
          CommandController::instance()->execute(command);
        }
    }
  }

  this->scene->setCurrentFrame(frame_nmb);
  showAnnotationsOfFrame(f);
  this->scene->update();
}

void Player::showAnnotationsOfFrame(shared_ptr<AnnotatorLib::Frame> frame) {
  clearAnnotationsGraphics();

  for (shared_ptr<AnnotatorLib::Annotation> annotation :
       AnnotatorLib::Algo::InterpolateAnnotation::getInterpolations(
           this->session, frame)) {

    AnnotationGraphicsItem *graphicsItem =
        AnnotationGraphicsItemFactory::createItem(annotation);

    connect(SelectionController::instance(),
            SIGNAL(signal_objectSelection(shared_ptr<AnnotatorLib::Object>)),
            graphicsItem,
            SLOT(on_objectSelected(shared_ptr<AnnotatorLib::Object>)));

    graphicsItem->setPlayer(this);
    scene->addItem(graphicsItem);
    annotationGraphics.push_back(graphicsItem);
  }

//  // if nothing is selected take first annotation
//  if (!SelectionController::instance()->getSelectedObject()) {
//    if (annotationGraphics.empty()) {
//      SelectionController::instance()->setSelectedObject(nullptr);
//    }
//  }
}

/**
 * updateHorizontalSlider	-	update the progress bar
 *
 */
void Player::updateHorizontalSlider() {
  // update the progress bar
  ui->horizontalSlider->setValue(videoplayer->getCurFrameNr());
  updateTimeLabel();
}

void Player::on_horizontalSlider_sliderMoved(int newpos) {
  long pos =
      newpos * videoplayer->getTotalFrameNr() / ui->horizontalSlider->maximum();
  on_frameSelected(pos);
}

/**
 * setSliderValue	-	set new value on the progress bar
 *
*/
void Player::setSliderValue(int newpos) {
  ui->horizontalSlider->setValue(newpos);
  on_horizontalSlider_sliderMoved(newpos);
}

void Player::on_frameSelected(long index) {
  this->videoplayer->on_frameSelected(index - 1); // why -1?
  updateTimeLabel();
  updateHorizontalSlider();
}

/**
 * updateTimeLabel	-	update Time Label
 */
void Player::updateTimeLabel() {

  double pos_ms = 0;
  double length_ms = 0;
  long cfn = 0;
  long tfn = 0;
  if (this->videoplayer->isOpened()) {
    pos_ms = videoplayer->getPositionMS();
    length_ms = videoplayer->getLengthMS();
    cfn = videoplayer->getCurFrameNr();
    tfn = videoplayer->getTotalFrameNr();
  }
  QString curPos =
      QDateTime::fromMSecsSinceEpoch(pos_ms - 3600000)
          .toString("hh:mm:ss");

  QString length =
      QDateTime::fromMSecsSinceEpoch(length_ms - 3600000)
          .toString("hh:mm:ss");

  ui->timeLabel->setText(tr(""
                            "%1 / %2")
                             .arg(curPos, length));

  ui->frameNrLabel->setText(
      tr(""
         "%1 / %2")
          .arg(QString::number(cfn), QString::number(tfn)));
}

/**
 * play	-	play the video
 *
 */
void Player::play() {
  // video->setDelay(1000.f / video->getFrameRate());
  videoplayer->playIt();
}

/**
 * pause	-	pause the video
 *
 */
void Player::pause() { videoplayer->pauseIt(); }

/**
 * sleep	-	pause the video for several msecs
 *
 * @param msecs
 */
void Player::sleep(int msecs) { videoplayer->wait(msecs); }

///#################################################################################################///

void Player::reload() {
  this->videoplayer->reload();
  // TODO: reload annotations?
}

void Player::enableDrawing(bool enable)
{
  this->ui->scrollArea->setEnabled(enable);
}

/**
 * update the video speed by a factor f in percent
 *
 */
void Player::on_speedSpinBox_valueChanged(int f) {
  // TODO: set proper framerate
  videoplayer->setDelay((100.f * videoplayer->getFrameRate()) / (float)f);
}

///#########################################SLOTS###########################################///

void Player::on_btnPlay_clicked() { play(); }

void Player::on_btnPause_clicked() { pause(); }

void Player::on_btnStop_clicked() { videoplayer->stopIt(); }

void Player::on_btnPrev_clicked() {
  // this->setAutoAnnotation(false);
  videoplayer->prevFrame();
}

void Player::on_btnNext_clicked() { videoplayer->nextFrame(); }

void Player::on_autoAnnotate(bool enabled) {
  if (enabled)
    this->ui->speedSpinBox->setValue(100);
  else
    this->ui->speedSpinBox->setValue(50);
  this->autoAnnotation = enabled;
  //don't allow to jump back and forth, when plugin is busy...
  this->ui->trackbarWidget->setEnabled(!enabled);
  this->ui->btnPrev->setEnabled(!enabled);
}
<|endoftext|>


<commit_before>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
//

#include "client/ui/desktop_widget.h"

#include "base/logging.h"
#include "common/keycode_converter.h"
#include "client/ui/frame_qimage.h"

#include <QApplication>
#include <QWheelEvent>

#if defined(OS_LINUX)
#include <X11/XKBlib.h>
#if defined(KeyPress)
#undef KeyPress
#endif // defined(KeyPress)
#endif // defined(OS_LINUX)

namespace client {

namespace {

constexpr uint32_t kWheelMask = proto::MouseEvent::WHEEL_DOWN | proto::MouseEvent::WHEEL_UP;

bool isNumLockActivated()
{
#if defined(OS_WIN)
    return GetKeyState(VK_NUMLOCK) != 0;
#elif defined(OS_LINUX)
    Display* display = XOpenDisplay(nullptr);
    if (!display)
    {
        LOG(LS_WARNING) << "XOpenDisplay failed";
        return false;
    }

    unsigned state = 0;
    XkbGetIndicatorState(display, XkbUseCoreKbd, &state);
    XCloseDisplay(display);

    return (state & 2) != 0;
#else
#warning Platform support not implemented
    return false;
#endif // defined(OS_WIN)
}

bool isCapsLockActivated()
{
#if defined(OS_WIN)
    return GetKeyState(VK_CAPITAL) != 0;
#elif defined(OS_LINUX)
    Display* display = XOpenDisplay(nullptr);
    if (!display)
    {
        LOG(LS_WARNING) << "XOpenDisplay failed";
        return false;
    }

    unsigned state = 0;
    XkbGetIndicatorState(display, XkbUseCoreKbd, &state);
    XCloseDisplay(display);

    return (state & 1) != 0;
#else
#warning Platform support not implemented
    return false;
#endif // defined(OS_WIN)
}

bool isModifierKey(int key)
{
    return key == Qt::Key_Control || key == Qt::Key_Alt ||
           key == Qt::Key_Shift || key == Qt::Key_Meta;
}

} // namespace

DesktopWidget::DesktopWidget(Delegate* delegate, QWidget* parent)
    : QWidget(parent),
      delegate_(delegate)
{
    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    setFocusPolicy(Qt::StrongFocus);
    setAttribute(Qt::WA_OpaquePaintEvent);
    setAttribute(Qt::WA_NoSystemBackground);
    setMouseTracking(true);
}

base::Frame* DesktopWidget::desktopFrame()
{
    return frame_.get();
}

void DesktopWidget::setDesktopFrame(std::shared_ptr<base::Frame>& frame)
{
    frame_ = std::move(frame);
}

void DesktopWidget::doMouseEvent(QEvent::Type event_type,
                                 const Qt::MouseButtons& buttons,
                                 const QPoint& pos,
                                 const QPoint& delta)
{
    if (!frame_)
        return;

    uint32_t mask;

    if (event_type == QMouseEvent::MouseMove)
    {
        mask = prev_mask_;
    }
    else
    {
        mask = 0;

        if (buttons & Qt::LeftButton)
            mask |= proto::MouseEvent::LEFT_BUTTON;

        if (buttons & Qt::MiddleButton)
            mask |= proto::MouseEvent::MIDDLE_BUTTON;

        if (buttons & Qt::RightButton)
            mask |= proto::MouseEvent::RIGHT_BUTTON;
    }

    int wheel_steps = 0;

    if (event_type == QEvent::Wheel)
    {
        if (delta.y() < 0)
        {
            mask |= proto::MouseEvent::WHEEL_DOWN;
            wheel_steps = -delta.y() / QWheelEvent::DefaultDeltasPerStep;
        }
        else
        {
            mask |= proto::MouseEvent::WHEEL_UP;
            wheel_steps = delta.y() / QWheelEvent::DefaultDeltasPerStep;
        }

        if (!wheel_steps)
            wheel_steps = 1;
    }

    if (prev_pos_ != pos || prev_mask_ != mask)
    {
        prev_pos_ = pos;
        prev_mask_ = mask & ~kWheelMask;

        proto::MouseEvent event;
        event.set_x(pos.x());
        event.set_y(pos.y());
        event.set_mask(mask);

        if (mask & kWheelMask)
        {
            for (int i = 0; i < wheel_steps; ++i)
                delegate_->onMouseEvent(event);
        }
        else
        {
            delegate_->onMouseEvent(event);
        }
    }
}

void DesktopWidget::doKeyEvent(QKeyEvent* event)
{
    int key = event->key();
    if (key == Qt::Key_CapsLock || key == Qt::Key_NumLock)
        return;

    if (!enable_key_sequenses_ && isModifierKey(key))
        return;

    uint32_t flags = ((event->type() == QEvent::KeyPress) ? proto::KeyEvent::PRESSED : 0);

    flags |= (isCapsLockActivated() ? proto::KeyEvent::CAPSLOCK : 0);
    flags |= (isNumLockActivated() ? proto::KeyEvent::NUMLOCK : 0);

    uint32_t usb_keycode =
        common::KeycodeConverter::nativeKeycodeToUsbKeycode(event->nativeScanCode());
    if (usb_keycode == common::KeycodeConverter::invalidUsbKeycode())
        return;

    executeKeyEvent(usb_keycode, flags);
}

void DesktopWidget::executeKeyCombination(int key_sequence)
{
    const uint32_t kUsbCodeLeftAlt = 0x0700e2;
    const uint32_t kUsbCodeLeftCtrl = 0x0700e0;
    const uint32_t kUsbCodeLeftShift = 0x0700e1;
    const uint32_t kUsbCodeLeftMeta = 0x0700e3;

    uint32_t flags = 0;

    flags |= (isCapsLockActivated() ? proto::KeyEvent::CAPSLOCK : 0);
    flags |= (isNumLockActivated() ? proto::KeyEvent::NUMLOCK : 0);

    uint32_t key = common::KeycodeConverter::qtKeycodeToUsbKeycode(
        key_sequence & ~Qt::KeyboardModifierMask);
    if (key == common::KeycodeConverter::invalidUsbKeycode())
        return;

    proto::KeyEvent event;
    event.set_flags(flags | proto::KeyEvent::PRESSED);

    if (key_sequence & Qt::AltModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftAlt);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::ControlModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftCtrl);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::ShiftModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftShift);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::MetaModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftMeta);
        delegate_->onKeyEvent(event);
    }

    event.set_usb_keycode(key);
    delegate_->onKeyEvent(event);

    event.set_flags(flags);

    event.set_usb_keycode(key);
    delegate_->onKeyEvent(event);

    if (key_sequence & Qt::MetaModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftMeta);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::ShiftModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftShift);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::ControlModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftCtrl);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::AltModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftAlt);
        delegate_->onKeyEvent(event);
    }
}

void DesktopWidget::enableKeyCombinations(bool enable)
{
    enable_key_sequenses_ = enable;

#if defined(OS_WIN)
    if (enable)
        keyboard_hook_.reset(SetWindowsHookExW(WH_KEYBOARD_LL, keyboardHookProc, nullptr, 0));
    else
        keyboard_hook_.reset();
#endif // defined(OS_WIN)
}

void DesktopWidget::paintEvent(QPaintEvent* /* event */)
{
    FrameQImage* frame = reinterpret_cast<FrameQImage*>(frame_.get());
    if (frame)
    {
        painter_.begin(this);
        painter_.setRenderHint(QPainter::SmoothPixmapTransform);
        painter_.drawImage(rect(), frame->constImage());
        painter_.end();
    }

    delegate_->onDrawDesktop();
}

void DesktopWidget::mouseMoveEvent(QMouseEvent* event)
{
    doMouseEvent(event->type(), event->buttons(), event->pos());
}

void DesktopWidget::mousePressEvent(QMouseEvent* event)
{
    doMouseEvent(event->type(), event->buttons(), event->pos());
}

void DesktopWidget::mouseReleaseEvent(QMouseEvent* event)
{
    doMouseEvent(event->type(), event->buttons(), event->pos());
}

void DesktopWidget::mouseDoubleClickEvent(QMouseEvent* event)
{
    doMouseEvent(event->type(), event->buttons(), event->pos());
}

void DesktopWidget::keyPressEvent(QKeyEvent* event)
{
    doKeyEvent(event);
}

void DesktopWidget::keyReleaseEvent(QKeyEvent* event)
{
    doKeyEvent(event);
}

void DesktopWidget::leaveEvent(QEvent* event)
{
#if defined(OS_WIN)
    keyboard_hook_.reset();
#endif // defined(OS_WIN)

    // When the mouse cursor leaves the widget area, release all the mouse buttons.
    if (prev_mask_ != 0)
    {
        proto::MouseEvent mouse_event;
        mouse_event.set_x(prev_pos_.x());
        mouse_event.set_y(prev_pos_.y());

        delegate_->onMouseEvent(mouse_event);
        prev_mask_ = 0;
    }

    QWidget::leaveEvent(event);
}

void DesktopWidget::focusInEvent(QFocusEvent* event)
{
#if defined(OS_WIN)
    if (enable_key_sequenses_)
        keyboard_hook_.reset(SetWindowsHookExW(WH_KEYBOARD_LL, keyboardHookProc, nullptr, 0));
#endif // defined(OS_WIN)

    QWidget::focusInEvent(event);
}

void DesktopWidget::focusOutEvent(QFocusEvent* event)
{
#if defined(OS_WIN)
    keyboard_hook_.reset();
#endif // defined(OS_WIN)

    // Release all pressed keys of the keyboard.
    if (!pressed_keys_.empty())
    {
        uint32_t flags = 0;

        flags |= (isCapsLockActivated() ? proto::KeyEvent::CAPSLOCK : 0);
        flags |= (isNumLockActivated() ? proto::KeyEvent::NUMLOCK : 0);

        proto::KeyEvent key_event;
        key_event.set_flags(flags);

        auto it = pressed_keys_.begin();
        while (it != pressed_keys_.end())
        {
            key_event.set_usb_keycode(*it);
            delegate_->onKeyEvent(key_event);
            it = pressed_keys_.erase(it);
        }
    }

    QWidget::focusOutEvent(event);
}

void DesktopWidget::executeKeyEvent(uint32_t usb_keycode, uint32_t flags)
{
    if (flags & proto::KeyEvent::PRESSED)
        pressed_keys_.insert(usb_keycode);
    else
        pressed_keys_.erase(usb_keycode);

    proto::KeyEvent event;
    event.set_usb_keycode(usb_keycode);
    event.set_flags(flags);

    delegate_->onKeyEvent(event);
}

#if defined(OS_WIN)
// static
LRESULT CALLBACK DesktopWidget::keyboardHookProc(INT code, WPARAM wparam, LPARAM lparam)
{
    if (code == HC_ACTION)
    {
        DesktopWidget* self = dynamic_cast<DesktopWidget*>(QApplication::focusWidget());
        if (self)
        {
            KBDLLHOOKSTRUCT* hook = reinterpret_cast<KBDLLHOOKSTRUCT*>(lparam);

            if (hook->vkCode != VK_CAPITAL && hook->vkCode != VK_NUMLOCK)
            {
                uint32_t flags = ((wparam == WM_KEYDOWN || wparam == WM_SYSKEYDOWN) ?
                                  proto::KeyEvent::PRESSED : 0);

                flags |= (isCapsLockActivated() ? proto::KeyEvent::CAPSLOCK : 0);
                flags |= (isNumLockActivated() ? proto::KeyEvent::NUMLOCK : 0);

                uint32_t scan_code = hook->scanCode;

                if (hook->flags & LLKHF_EXTENDED)
                    scan_code |= 0x100;

                uint32_t usb_keycode =
                    common::KeycodeConverter::nativeKeycodeToUsbKeycode(scan_code);
                if (usb_keycode != common::KeycodeConverter::invalidUsbKeycode())
                {
                    self->executeKeyEvent(usb_keycode, flags);
                    return TRUE;
                }
            }
        }
    }

    return CallNextHookEx(nullptr, code, wparam, lparam);
}
#endif // defined(OS_WIN)

} // namespace client
<commit_msg>Implement isNumLockActivated/isCapsLockActivated for MacOS.<commit_after>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
//

#include "client/ui/desktop_widget.h"

#include "base/logging.h"
#include "common/keycode_converter.h"
#include "client/ui/frame_qimage.h"

#include <QApplication>
#include <QWheelEvent>

#if defined(OS_LINUX)
#include <X11/XKBlib.h>
#if defined(KeyPress)
#undef KeyPress
#endif // defined(KeyPress)
#endif // defined(OS_LINUX)

#if defined(OS_MAC)
#include <CoreGraphics/CGEventSource.h>
#endif // defined(OS_MAC)

namespace client {

namespace {

constexpr uint32_t kWheelMask = proto::MouseEvent::WHEEL_DOWN | proto::MouseEvent::WHEEL_UP;

bool isNumLockActivated()
{
#if defined(OS_WIN)
    return GetKeyState(VK_NUMLOCK) != 0;
#elif defined(OS_LINUX)
    Display* display = XOpenDisplay(nullptr);
    if (!display)
    {
        LOG(LS_WARNING) << "XOpenDisplay failed";
        return false;
    }

    unsigned state = 0;
    XkbGetIndicatorState(display, XkbUseCoreKbd, &state);
    XCloseDisplay(display);

    return (state & 2) != 0;
#elif defined(OS_MAC)
    // Without NumLock.
    return false;
#else
#warning Platform support not implemented
    return false;
#endif // defined(OS_WIN)
}

bool isCapsLockActivated()
{
#if defined(OS_WIN)
    return GetKeyState(VK_CAPITAL) != 0;
#elif defined(OS_LINUX)
    Display* display = XOpenDisplay(nullptr);
    if (!display)
    {
        LOG(LS_WARNING) << "XOpenDisplay failed";
        return false;
    }

    unsigned state = 0;
    XkbGetIndicatorState(display, XkbUseCoreKbd, &state);
    XCloseDisplay(display);

    return (state & 1) != 0;
#elif defined(OS_MAC)
    CGEventFlags event_flags = CGEventSourceFlagsState(kCGEventSourceStateCombinedSessionState);
    return (event_flags & kCGEventFlagMaskAlphaShift) != 0;
#else
#warning Platform support not implemented
    return false;
#endif // defined(OS_WIN)
}

bool isModifierKey(int key)
{
    return key == Qt::Key_Control || key == Qt::Key_Alt ||
           key == Qt::Key_Shift || key == Qt::Key_Meta;
}

} // namespace

DesktopWidget::DesktopWidget(Delegate* delegate, QWidget* parent)
    : QWidget(parent),
      delegate_(delegate)
{
    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    setFocusPolicy(Qt::StrongFocus);
    setAttribute(Qt::WA_OpaquePaintEvent);
    setAttribute(Qt::WA_NoSystemBackground);
    setMouseTracking(true);
}

base::Frame* DesktopWidget::desktopFrame()
{
    return frame_.get();
}

void DesktopWidget::setDesktopFrame(std::shared_ptr<base::Frame>& frame)
{
    frame_ = std::move(frame);
}

void DesktopWidget::doMouseEvent(QEvent::Type event_type,
                                 const Qt::MouseButtons& buttons,
                                 const QPoint& pos,
                                 const QPoint& delta)
{
    if (!frame_)
        return;

    uint32_t mask;

    if (event_type == QMouseEvent::MouseMove)
    {
        mask = prev_mask_;
    }
    else
    {
        mask = 0;

        if (buttons & Qt::LeftButton)
            mask |= proto::MouseEvent::LEFT_BUTTON;

        if (buttons & Qt::MiddleButton)
            mask |= proto::MouseEvent::MIDDLE_BUTTON;

        if (buttons & Qt::RightButton)
            mask |= proto::MouseEvent::RIGHT_BUTTON;
    }

    int wheel_steps = 0;

    if (event_type == QEvent::Wheel)
    {
        if (delta.y() < 0)
        {
            mask |= proto::MouseEvent::WHEEL_DOWN;
            wheel_steps = -delta.y() / QWheelEvent::DefaultDeltasPerStep;
        }
        else
        {
            mask |= proto::MouseEvent::WHEEL_UP;
            wheel_steps = delta.y() / QWheelEvent::DefaultDeltasPerStep;
        }

        if (!wheel_steps)
            wheel_steps = 1;
    }

    if (prev_pos_ != pos || prev_mask_ != mask)
    {
        prev_pos_ = pos;
        prev_mask_ = mask & ~kWheelMask;

        proto::MouseEvent event;
        event.set_x(pos.x());
        event.set_y(pos.y());
        event.set_mask(mask);

        if (mask & kWheelMask)
        {
            for (int i = 0; i < wheel_steps; ++i)
                delegate_->onMouseEvent(event);
        }
        else
        {
            delegate_->onMouseEvent(event);
        }
    }
}

void DesktopWidget::doKeyEvent(QKeyEvent* event)
{
    int key = event->key();
    if (key == Qt::Key_CapsLock || key == Qt::Key_NumLock)
        return;

    if (!enable_key_sequenses_ && isModifierKey(key))
        return;

    uint32_t flags = ((event->type() == QEvent::KeyPress) ? proto::KeyEvent::PRESSED : 0);

    flags |= (isCapsLockActivated() ? proto::KeyEvent::CAPSLOCK : 0);
    flags |= (isNumLockActivated() ? proto::KeyEvent::NUMLOCK : 0);

    uint32_t usb_keycode =
        common::KeycodeConverter::nativeKeycodeToUsbKeycode(event->nativeScanCode());
    if (usb_keycode == common::KeycodeConverter::invalidUsbKeycode())
        return;

    executeKeyEvent(usb_keycode, flags);
}

void DesktopWidget::executeKeyCombination(int key_sequence)
{
    const uint32_t kUsbCodeLeftAlt = 0x0700e2;
    const uint32_t kUsbCodeLeftCtrl = 0x0700e0;
    const uint32_t kUsbCodeLeftShift = 0x0700e1;
    const uint32_t kUsbCodeLeftMeta = 0x0700e3;

    uint32_t flags = 0;

    flags |= (isCapsLockActivated() ? proto::KeyEvent::CAPSLOCK : 0);
    flags |= (isNumLockActivated() ? proto::KeyEvent::NUMLOCK : 0);

    uint32_t key = common::KeycodeConverter::qtKeycodeToUsbKeycode(
        key_sequence & ~Qt::KeyboardModifierMask);
    if (key == common::KeycodeConverter::invalidUsbKeycode())
        return;

    proto::KeyEvent event;
    event.set_flags(flags | proto::KeyEvent::PRESSED);

    if (key_sequence & Qt::AltModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftAlt);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::ControlModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftCtrl);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::ShiftModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftShift);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::MetaModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftMeta);
        delegate_->onKeyEvent(event);
    }

    event.set_usb_keycode(key);
    delegate_->onKeyEvent(event);

    event.set_flags(flags);

    event.set_usb_keycode(key);
    delegate_->onKeyEvent(event);

    if (key_sequence & Qt::MetaModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftMeta);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::ShiftModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftShift);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::ControlModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftCtrl);
        delegate_->onKeyEvent(event);
    }

    if (key_sequence & Qt::AltModifier)
    {
        event.set_usb_keycode(kUsbCodeLeftAlt);
        delegate_->onKeyEvent(event);
    }
}

void DesktopWidget::enableKeyCombinations(bool enable)
{
    enable_key_sequenses_ = enable;

#if defined(OS_WIN)
    if (enable)
        keyboard_hook_.reset(SetWindowsHookExW(WH_KEYBOARD_LL, keyboardHookProc, nullptr, 0));
    else
        keyboard_hook_.reset();
#endif // defined(OS_WIN)
}

void DesktopWidget::paintEvent(QPaintEvent* /* event */)
{
    FrameQImage* frame = reinterpret_cast<FrameQImage*>(frame_.get());
    if (frame)
    {
        painter_.begin(this);
        painter_.setRenderHint(QPainter::SmoothPixmapTransform);
        painter_.drawImage(rect(), frame->constImage());
        painter_.end();
    }

    delegate_->onDrawDesktop();
}

void DesktopWidget::mouseMoveEvent(QMouseEvent* event)
{
    doMouseEvent(event->type(), event->buttons(), event->pos());
}

void DesktopWidget::mousePressEvent(QMouseEvent* event)
{
    doMouseEvent(event->type(), event->buttons(), event->pos());
}

void DesktopWidget::mouseReleaseEvent(QMouseEvent* event)
{
    doMouseEvent(event->type(), event->buttons(), event->pos());
}

void DesktopWidget::mouseDoubleClickEvent(QMouseEvent* event)
{
    doMouseEvent(event->type(), event->buttons(), event->pos());
}

void DesktopWidget::keyPressEvent(QKeyEvent* event)
{
    doKeyEvent(event);
}

void DesktopWidget::keyReleaseEvent(QKeyEvent* event)
{
    doKeyEvent(event);
}

void DesktopWidget::leaveEvent(QEvent* event)
{
#if defined(OS_WIN)
    keyboard_hook_.reset();
#endif // defined(OS_WIN)

    // When the mouse cursor leaves the widget area, release all the mouse buttons.
    if (prev_mask_ != 0)
    {
        proto::MouseEvent mouse_event;
        mouse_event.set_x(prev_pos_.x());
        mouse_event.set_y(prev_pos_.y());

        delegate_->onMouseEvent(mouse_event);
        prev_mask_ = 0;
    }

    QWidget::leaveEvent(event);
}

void DesktopWidget::focusInEvent(QFocusEvent* event)
{
#if defined(OS_WIN)
    if (enable_key_sequenses_)
        keyboard_hook_.reset(SetWindowsHookExW(WH_KEYBOARD_LL, keyboardHookProc, nullptr, 0));
#endif // defined(OS_WIN)

    QWidget::focusInEvent(event);
}

void DesktopWidget::focusOutEvent(QFocusEvent* event)
{
#if defined(OS_WIN)
    keyboard_hook_.reset();
#endif // defined(OS_WIN)

    // Release all pressed keys of the keyboard.
    if (!pressed_keys_.empty())
    {
        uint32_t flags = 0;

        flags |= (isCapsLockActivated() ? proto::KeyEvent::CAPSLOCK : 0);
        flags |= (isNumLockActivated() ? proto::KeyEvent::NUMLOCK : 0);

        proto::KeyEvent key_event;
        key_event.set_flags(flags);

        auto it = pressed_keys_.begin();
        while (it != pressed_keys_.end())
        {
            key_event.set_usb_keycode(*it);
            delegate_->onKeyEvent(key_event);
            it = pressed_keys_.erase(it);
        }
    }

    QWidget::focusOutEvent(event);
}

void DesktopWidget::executeKeyEvent(uint32_t usb_keycode, uint32_t flags)
{
    if (flags & proto::KeyEvent::PRESSED)
        pressed_keys_.insert(usb_keycode);
    else
        pressed_keys_.erase(usb_keycode);

    proto::KeyEvent event;
    event.set_usb_keycode(usb_keycode);
    event.set_flags(flags);

    delegate_->onKeyEvent(event);
}

#if defined(OS_WIN)
// static
LRESULT CALLBACK DesktopWidget::keyboardHookProc(INT code, WPARAM wparam, LPARAM lparam)
{
    if (code == HC_ACTION)
    {
        DesktopWidget* self = dynamic_cast<DesktopWidget*>(QApplication::focusWidget());
        if (self)
        {
            KBDLLHOOKSTRUCT* hook = reinterpret_cast<KBDLLHOOKSTRUCT*>(lparam);

            if (hook->vkCode != VK_CAPITAL && hook->vkCode != VK_NUMLOCK)
            {
                uint32_t flags = ((wparam == WM_KEYDOWN || wparam == WM_SYSKEYDOWN) ?
                                  proto::KeyEvent::PRESSED : 0);

                flags |= (isCapsLockActivated() ? proto::KeyEvent::CAPSLOCK : 0);
                flags |= (isNumLockActivated() ? proto::KeyEvent::NUMLOCK : 0);

                uint32_t scan_code = hook->scanCode;

                if (hook->flags & LLKHF_EXTENDED)
                    scan_code |= 0x100;

                uint32_t usb_keycode =
                    common::KeycodeConverter::nativeKeycodeToUsbKeycode(scan_code);
                if (usb_keycode != common::KeycodeConverter::invalidUsbKeycode())
                {
                    self->executeKeyEvent(usb_keycode, flags);
                    return TRUE;
                }
            }
        }
    }

    return CallNextHookEx(nullptr, code, wparam, lparam);
}
#endif // defined(OS_WIN)

} // namespace client
<|endoftext|>


<commit_before>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_STATEWRAPPER_H_
#define LUWRA_STATEWRAPPER_H_

#include "common.hpp"
#include "auxiliary.hpp"

#include <string>
#include <utility>

LUWRA_NS_BEGIN

/**
 * Accessor for an entry in the global namespace
 */
struct GlobalAccessor {
	State* state;
	std::string key;

	inline
	GlobalAccessor(State* state, const std::string& key): state(state), key(key) {}

	/**
	 * Assign a new value.
	 */
	template <typename V> inline
	GlobalAccessor& set(V value) {
		setGlobal(state, key, value);
		return *this;
	}

	/**
	 * Shortcut for `set()`
	 */
	template <typename V> inline
	GlobalAccessor& operator =(V value) {
		return set<V>(value);
	}

	/**
	 * Retrieve the associated value.
	 */
	template <typename V> inline
	V get() {
		return getGlobal<V>(state, key);
	}

	/**
	 * Shortcut for `get()`
	 */
	template <typename V> inline
	operator V() {
		return get<V>();
	}
};

/**
 * Wrapper for a Lua state
 */
struct StateWrapper {
	State* state;
	bool close_state;

	/**
	 * Operate on a foreign state instance.
	 */
	inline
	StateWrapper(State* state): state(state), close_state(false) {}

	/**
	 * Create a new Lua state.
	 */
	inline
	StateWrapper(): state(luaL_newstate()), close_state(true) {}

	inline
	~StateWrapper() {
		if (close_state)
			lua_close(state);
	}

	inline
	operator State*() {
		return state;
	}

	inline
	void loadStandardLibrary() {
		luaL_openlibs(state);
	}

	/**
	 * Retrieve a global value.
	 */
	template <typename V> inline
	V getGlobal(const std::string& key) const {
		return getGlobal<V>(state, key);
	}

	/**
	 * Assign a global value.
	 */
	template <typename V> inline
	void setGlobal(const std::string& key, V value) const {
		setGlobal(state, key, value);
	}

	/**
	 * Create an accessor to a global value.
	 */
	inline
	GlobalAccessor operator [](const std::string& key) const {
		return GlobalAccessor(state, key);
	}

	/**
	 * See [luwra::registerUserType](@ref luwra::registerUserType).
	 */
	template <typename T> inline
	void registerUserType(
		const std::string& ctor_name,
		const MemberMap& methods = MemberMap(),
		const MemberMap& meta_methods = MemberMap()
	) {
		registerUserType<T>(state, ctor_name, methods, meta_methods);
	}

	/**
	 * Execute a piece of code.
	 */
	inline
	int runString(const std::string& code) {
		return luaL_dostring(state, code.c_str());
	}

	/**
	 * Execute a file.
	 */
	inline
	int runFile(const std::string& filepath) {
		return luaL_dofile(state, filepath.c_str());
	}
};

LUWRA_NS_END

#endif
<commit_msg>Make sure StateWrapper calls the correct functions<commit_after>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_STATEWRAPPER_H_
#define LUWRA_STATEWRAPPER_H_

#include "common.hpp"
#include "auxiliary.hpp"

#include <string>
#include <utility>

LUWRA_NS_BEGIN

/**
 * Accessor for an entry in the global namespace
 */
struct GlobalAccessor {
	State* state;
	std::string key;

	inline
	GlobalAccessor(State* state, const std::string& key): state(state), key(key) {}

	/**
	 * Assign a new value.
	 */
	template <typename V> inline
	GlobalAccessor& set(V value) {
		setGlobal(state, key, value);
		return *this;
	}

	/**
	 * Shortcut for `set()`
	 */
	template <typename V> inline
	GlobalAccessor& operator =(V value) {
		return set<V>(value);
	}

	/**
	 * Retrieve the associated value.
	 */
	template <typename V> inline
	V get() {
		return getGlobal<V>(state, key);
	}

	/**
	 * Shortcut for `get()`
	 */
	template <typename V> inline
	operator V() {
		return get<V>();
	}
};

/**
 * Wrapper for a Lua state
 */
struct StateWrapper {
	State* state;
	bool close_state;

	/**
	 * Operate on a foreign state instance.
	 */
	inline
	StateWrapper(State* state): state(state), close_state(false) {}

	/**
	 * Create a new Lua state.
	 */
	inline
	StateWrapper(): state(luaL_newstate()), close_state(true) {}

	inline
	~StateWrapper() {
		if (close_state)
			lua_close(state);
	}

	inline
	operator State*() {
		return state;
	}

	inline
	void loadStandardLibrary() {
		luaL_openlibs(state);
	}

	/**
	 * Retrieve a global value.
	 */
	template <typename V> inline
	V getGlobal(const std::string& key) const {
		return ::luwra::getGlobal<V>(state, key);
	}

	/**
	 * Assign a global value.
	 */
	template <typename V> inline
	void setGlobal(const std::string& key, V value) const {
		::luwra::setGlobal(state, key, value);
	}

	/**
	 * Create an accessor to a global value.
	 */
	inline
	GlobalAccessor operator [](const std::string& key) const {
		return GlobalAccessor(state, key);
	}

	/**
	 * See [luwra::registerUserType](@ref luwra::registerUserType).
	 */
	template <typename T> inline
	void registerUserType(
		const std::string& ctor_name,
		const MemberMap& methods = MemberMap(),
		const MemberMap& meta_methods = MemberMap()
	) {
		::luwra::registerUserType<T>(state, ctor_name, methods, meta_methods);
	}

	/**
	 * Execute a piece of code.
	 */
	inline
	int runString(const std::string& code) {
		return luaL_dostring(state, code.c_str());
	}

	/**
	 * Execute a file.
	 */
	inline
	int runFile(const std::string& filepath) {
		return luaL_dofile(state, filepath.c_str());
	}
};

LUWRA_NS_END

#endif
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <stack>
#include <string>

using namespace std;

typedef struct node {
    string val;
    bool visited = false;
    vector < node >  neighbors ;
} node;

typedef vector < node >  list_nodes;

void dfs(node start){
    stack<node> s;
    s.push(start);
    while(s.empty() == false){
        node top = s.top();
        s.pop();

        if (top.visited == false){
            top.visited  = true;
            cout << "Node " << top.val << " visited" << endl;
            //Check for the termination condition
            list_nodes n = top.neighbors;
            for (node a: n){
                s.push(a);
            }
        }

    }
}

int main(){

     /*          a
     *        /    \
     *       b      c
     *       |    /   \
     *       d   e     f
     *
     */

    node a,b,c,d,e,f;
    a.val = "a";
    b.val = "b";
    c.val = "c";
    d.val = "d";
    e.val = "e";
    f.val = "f";

    list_nodes la(2), lc(2), lb(1);

    lc[0] = e;
    lc[1] = f;
    c.neighbors = lc;

    lb[0] = d;
    b.neighbors = lb;

    la[0] = b;
    la[1] = c;
    a.neighbors = la;

    cout<< " dfs -> a" <<endl<<endl;
    dfs(a);

    return 0;

}
<commit_msg>Add beautiful implementation dfs.<commit_after>#include <bits/stdc++.h>
#define NUM_NODES 8

using namespace std;

vector < int > g[NUM_NODES];
int vis[NUM_NODES];
enum {WHITE, GRAY, BLACK};

/*
 * o -> origin
 */
void dfs(int o){
    vis [o] = GRAY; //semi-visited
    for (int i = 0; i < g[o].size(); i++){
        int v = g[o][i];
        if (vis[v] == WHITE) dfs(v); // visit neighbors
    }
    cout << o << endl;
    vis[o] = BLACK; //visited;
}

int main(){

    g[0].push_back(1);
    g[0].push_back(2);
    g[0].push_back(3);
    g[1].push_back(4);
    g[1].push_back(5);
    g[2].push_back(6);
    g[3].push_back(7);

    dfs(0);

    return 0;
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "BackendPasses.h"

#include "llvm/Analysis/InlineCost.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/InlinerPass.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CodeGenOptions.h"

using namespace cling;
using namespace clang;
using namespace llvm;
using namespace llvm::legacy;

namespace {

  class InlinerKeepDeadFunc: public Inliner {
    Inliner* m_Inliner; // the actual inliner
    static char ID; // Pass identification, replacement for typeid
  public:
    InlinerKeepDeadFunc():
    Inliner(ID), m_Inliner(0) { }
    InlinerKeepDeadFunc(Pass* I):
    Inliner(ID), m_Inliner((Inliner*)I) { }

    using llvm::Pass::doInitialization;
    bool doInitialization(CallGraph &CG) override {
      // Forward out Resolver now that we are registered.
      if (!m_Inliner->getResolver())
        m_Inliner->setResolver(getResolver());
      return m_Inliner->doInitialization(CG); // no Module modification
    }

    InlineCost getInlineCost(CallSite CS) override {
      return m_Inliner->getInlineCost(CS);
    }
    void getAnalysisUsage(AnalysisUsage &AU) const override {
      m_Inliner->getAnalysisUsage(AU);
    }
    bool runOnSCC(CallGraphSCC &SCC) override {
      return m_Inliner->runOnSCC(SCC);
    }

    using llvm::Pass::doFinalization;
    // No-op: we need to keep the inlined functions for later use.
    bool doFinalization(CallGraph& /*CG*/) override {
      // Module is unchanged
      return false;
    }
  };
} // end anonymous namespace

// Pass registration. Luckily all known inliners depend on the same set
// of passes.
char InlinerKeepDeadFunc::ID = 0;

BackendPasses::BackendPasses(const CodeGenOptions &CGOpts,
                             const clang::TargetOptions &TOpts,
                             const LangOptions &LOpts):
  m_CodeGenOptsVerifyModule(CGOpts.VerifyModule)
{
  CreatePasses(CGOpts, TOpts, LOpts);
}

BackendPasses::~BackendPasses() {
  delete m_PMBuilder->Inliner;
}

void BackendPasses::CreatePasses(const CodeGenOptions &CGOpts,
                                 const clang::TargetOptions &TOpts,
                                 const LangOptions &LOpts)
{
  // From BackEndUtil's clang::EmitAssemblyHelper::CreatePasses().

  unsigned OptLevel = CGOpts.OptimizationLevel;

  // CodeGenOptions::InliningMethod Inlining = CGOpts.getInlining();
  CodeGenOptions::InliningMethod Inlining = CodeGenOptions::NormalInlining;

  // Handle disabling of LLVM optimization, where we want to preserve the
  // internal module before any optimization.
  if (CGOpts.DisableLLVMOpts) {
    OptLevel = 0;
    // Always keep at least ForceInline - NoInlining is deadly for libc++.
    // Inlining = CGOpts.NoInlining;
  }

  OptLevel = 1;

  m_PMBuilder.reset(new PassManagerBuilder());
  m_PMBuilder->OptLevel = OptLevel;
  m_PMBuilder->SizeLevel = CGOpts.OptimizeSize;
  m_PMBuilder->BBVectorize = CGOpts.VectorizeBB;
  m_PMBuilder->SLPVectorize = CGOpts.VectorizeSLP;
  m_PMBuilder->LoopVectorize = CGOpts.VectorizeLoop;

  m_PMBuilder->DisableTailCalls = CGOpts.DisableTailCalls;
  m_PMBuilder->DisableUnitAtATime = !CGOpts.UnitAtATime;
  m_PMBuilder->DisableUnrollLoops = !CGOpts.UnrollLoops;
  m_PMBuilder->MergeFunctions = CGOpts.MergeFunctions;
  m_PMBuilder->RerollLoops = CGOpts.RerollLoops;

  switch (Inlining) {
    case CodeGenOptions::NoInlining: {
      assert(0 && "libc++ requires at least OnlyAlwaysInlining!");
      break;
    }
    case CodeGenOptions::NormalInlining: {
      m_PMBuilder->Inliner =
        new InlinerKeepDeadFunc(createFunctionInliningPass(OptLevel,
                                                          CGOpts.OptimizeSize));
      break;
    }
    case CodeGenOptions::OnlyAlwaysInlining:
      // Respect always_inline.
      if (OptLevel == 0)
        // Do not insert lifetime intrinsics at -O0.
        m_PMBuilder->Inliner
          = new InlinerKeepDeadFunc(createAlwaysInlinerPass(false));
      else
        m_PMBuilder->Inliner
          = new InlinerKeepDeadFunc(createAlwaysInlinerPass());
      break;
  }

  // Set up the per-module pass manager.
  m_MPM.reset(new legacy::PassManager());
  //m_MPM->add(createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
  //if (!CGOpts.RewriteMapFiles.empty())
  //  addSymbolRewriterPass(CGOpts, m_MPM);

  m_PMBuilder->populateModulePassManager(*m_MPM);
}

void BackendPasses::runOnModule(Module& M) {

  // Set up the per-function pass manager.
  legacy::FunctionPassManager FPM(&M);
  //FPM.add(createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
  if (m_CodeGenOptsVerifyModule)
      FPM.add(createVerifierPass());
  m_PMBuilder->populateFunctionPassManager(FPM);

  // Run the per-function passes on the module.
  FPM.doInitialization();
  for (auto&& I: M.functions())
    if (!I.isDeclaration())
      FPM.run(I);
  FPM.doFinalization();

  m_MPM->run(M);
}
<commit_msg>Force OptLevel=0: all "unused" values might be used later, do not optimize them away.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "BackendPasses.h"

#include "llvm/Analysis/InlineCost.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/InlinerPass.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CodeGenOptions.h"

using namespace cling;
using namespace clang;
using namespace llvm;
using namespace llvm::legacy;

namespace {

  class InlinerKeepDeadFunc: public Inliner {
    Inliner* m_Inliner; // the actual inliner
    static char ID; // Pass identification, replacement for typeid
  public:
    InlinerKeepDeadFunc():
    Inliner(ID), m_Inliner(0) { }
    InlinerKeepDeadFunc(Pass* I):
    Inliner(ID), m_Inliner((Inliner*)I) { }

    using llvm::Pass::doInitialization;
    bool doInitialization(CallGraph &CG) override {
      // Forward out Resolver now that we are registered.
      if (!m_Inliner->getResolver())
        m_Inliner->setResolver(getResolver());
      return m_Inliner->doInitialization(CG); // no Module modification
    }

    InlineCost getInlineCost(CallSite CS) override {
      return m_Inliner->getInlineCost(CS);
    }
    void getAnalysisUsage(AnalysisUsage &AU) const override {
      m_Inliner->getAnalysisUsage(AU);
    }
    bool runOnSCC(CallGraphSCC &SCC) override {
      return m_Inliner->runOnSCC(SCC);
    }

    using llvm::Pass::doFinalization;
    // No-op: we need to keep the inlined functions for later use.
    bool doFinalization(CallGraph& /*CG*/) override {
      // Module is unchanged
      return false;
    }
  };
} // end anonymous namespace

// Pass registration. Luckily all known inliners depend on the same set
// of passes.
char InlinerKeepDeadFunc::ID = 0;

BackendPasses::BackendPasses(const CodeGenOptions &CGOpts,
                             const clang::TargetOptions &TOpts,
                             const LangOptions &LOpts):
  m_CodeGenOptsVerifyModule(CGOpts.VerifyModule)
{
  CreatePasses(CGOpts, TOpts, LOpts);
}

BackendPasses::~BackendPasses() {
  delete m_PMBuilder->Inliner;
}

void BackendPasses::CreatePasses(const CodeGenOptions &CGOpts,
                                 const clang::TargetOptions &TOpts,
                                 const LangOptions &LOpts)
{
  // From BackEndUtil's clang::EmitAssemblyHelper::CreatePasses().

  unsigned OptLevel = CGOpts.OptimizationLevel;

  // CodeGenOptions::InliningMethod Inlining = CGOpts.getInlining();
  CodeGenOptions::InliningMethod Inlining = CodeGenOptions::NormalInlining;

  // Handle disabling of LLVM optimization, where we want to preserve the
  // internal module before any optimization.
  if (CGOpts.DisableLLVMOpts) {
    OptLevel = 0;
    // Always keep at least ForceInline - NoInlining is deadly for libc++.
    // Inlining = CGOpts.NoInlining;
  }

  OptLevel = 0; // we need to keep even "unused" values - until we
  // feed incremental modules into the JIT.

  m_PMBuilder.reset(new PassManagerBuilder());
  m_PMBuilder->OptLevel = OptLevel;
  m_PMBuilder->SizeLevel = CGOpts.OptimizeSize;
  m_PMBuilder->BBVectorize = CGOpts.VectorizeBB;
  m_PMBuilder->SLPVectorize = CGOpts.VectorizeSLP;
  m_PMBuilder->LoopVectorize = CGOpts.VectorizeLoop;

  m_PMBuilder->DisableTailCalls = CGOpts.DisableTailCalls;
  m_PMBuilder->DisableUnitAtATime = !CGOpts.UnitAtATime;
  m_PMBuilder->DisableUnrollLoops = !CGOpts.UnrollLoops;
  m_PMBuilder->MergeFunctions = CGOpts.MergeFunctions;
  m_PMBuilder->RerollLoops = CGOpts.RerollLoops;

  switch (Inlining) {
    case CodeGenOptions::NoInlining: {
      assert(0 && "libc++ requires at least OnlyAlwaysInlining!");
      break;
    }
    case CodeGenOptions::NormalInlining: {
      m_PMBuilder->Inliner =
        new InlinerKeepDeadFunc(createFunctionInliningPass(OptLevel,
                                                          CGOpts.OptimizeSize));
      break;
    }
    case CodeGenOptions::OnlyAlwaysInlining:
      // Respect always_inline.
      if (OptLevel == 0)
        // Do not insert lifetime intrinsics at -O0.
        m_PMBuilder->Inliner
          = new InlinerKeepDeadFunc(createAlwaysInlinerPass(false));
      else
        m_PMBuilder->Inliner
          = new InlinerKeepDeadFunc(createAlwaysInlinerPass());
      break;
  }

  // Set up the per-module pass manager.
  m_MPM.reset(new legacy::PassManager());
  //m_MPM->add(createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
  //if (!CGOpts.RewriteMapFiles.empty())
  //  addSymbolRewriterPass(CGOpts, m_MPM);

  m_PMBuilder->populateModulePassManager(*m_MPM);
}

void BackendPasses::runOnModule(Module& M) {

  // Set up the per-function pass manager.
  legacy::FunctionPassManager FPM(&M);
  //FPM.add(createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
  if (m_CodeGenOptsVerifyModule)
      FPM.add(createVerifierPass());
  m_PMBuilder->populateFunctionPassManager(FPM);

  // Run the per-function passes on the module.
  FPM.doInitialization();
  for (auto&& I: M.functions())
    if (!I.isDeclaration())
      FPM.run(I);
  FPM.doFinalization();

  m_MPM->run(M);
}
<|endoftext|>