<commit_before>#include "balancer.hpp"

#define LB_VERBOSE 0
#if LB_VERBOSE
#define LBOUT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define LBOUT(fmt, ...) /** **/
#endif

using namespace std::chrono;

Balancer::Balancer(
       netstack_t& incoming, uint16_t in_port,
       netstack_t& outgoing, std::vector<net::Socket> nodelist)
  : netin(incoming), nodes()
{
  for (auto& addr : nodelist) {
    nodes.add_node(outgoing, addr, pool_signal_t{this, &Balancer::handle_queue});
  }

  netin.tcp().listen(in_port,
  [this] (auto conn) {
    if (conn != nullptr) this->incoming(conn);
  });
}

int Balancer::wait_queue() const {
  return queue.size();
}
void Balancer::incoming(tcp_ptr conn)
{
    queue.emplace_back(conn);
    LBOUT("Queueing connection (q=%lu)\n", queue.size());
    // see if LB needs more connections out
    this->handle_connections();
}
void Balancer::handle_queue()
{
  // check waitq
  while (nodes.pool_size() > 0 && queue.empty() == false)
  {
    auto& client = queue.front();
    if (client.conn->is_connected()) {
      // NOTE: explicitly want to copy buffers
      if (nodes.assign(client.conn, client.readq)) {
        queue.pop_front();
      }
    }
  } // waitq check
  // check if we need to create more connections
  this->handle_connections();
}
void Balancer::handle_connections()
{
  int np_connecting = nodes.pool_connecting();
  int estimate = queue.size() - (np_connecting + nodes.pool_size());
  estimate = std::min(estimate, MAX_OUTGOING_ATTEMPTS);
  estimate = std::max(0, estimate - np_connecting);
  if (estimate > 0)
  {
    try {
      // create more outgoing connections
      nodes.create_connections(estimate);
    }
    catch (std::exception& e)
    {
      if (this->rethrow_timer != Timers::UNUSED_ID)
          Timers::stop(this->rethrow_timer);
      // assuming the failure is due to not enough eph. ports
      this->rethrow_timer = Timers::oneshot(CONNECT_THROW_PERIOD,
      [this] (int) {
          this->rethrow_timer = Timers::UNUSED_ID;
          this->handle_connections();
      });
    }
  } // estimate
} // handle_connections()

Waiting::Waiting(tcp_ptr incoming)
  : conn(incoming), total(0)
{
  // queue incoming data from clients not yet
  // assigned to a node
  conn->on_read(READQ_PER_CLIENT,
  [this] (auto buf, size_t len) {
    // prevent buffer bloat attack
    total += len;
    if (total > MAX_READQ_PER_NODE) {
      conn->abort();
    }
    else {
      LBOUT("*** Queued %lu bytes\n", len);
      readq.emplace_back(buf, len);
    }
  });
}

template <typename... Args>
inline void Nodes::add_node(Args&&... args) {
  nodes.emplace_back(std::forward<Args> (args)...);
}
void Nodes::create_connections(int total)
{
  // temporary iterator
  for (int i = 0; i < total; i++)
  {
    // look for next active node up to *size* times
    for (size_t i = 0; i < nodes.size(); i++)
    {
      conn_iterator = (conn_iterator + 1) % nodes.size();
      if (nodes[conn_iterator].is_active()) break;
    }
    // only connect if node is determined active, to prevent
    // building up connect attempts on just one node
    if (nodes[conn_iterator].is_active()) {
      nodes[conn_iterator].connect();
    }
  }
}
bool Nodes::assign(tcp_ptr conn, queue_vector_t& readq)
{
  for (size_t i = 0; i < nodes.size(); i++)
  {
    auto outgoing = nodes[algo_iterator].get_connection();
    // algorithm here //
    algo_iterator = (algo_iterator + 1) % nodes.size();
    // check if connection was retrieved
    if (outgoing != nullptr)
    {
      assert(outgoing->is_connected());
      LBOUT("Assigning client to node %d (%s)\n",
            iterator, outgoing->to_string().c_str());
      this->create_session(conn, outgoing);
      // flush readq
      for (auto& buffer : readq) {
        LBOUT("*** Flushing %lu bytes\n", buffer.second);
        outgoing->write(std::move(buffer.first), buffer.second);
      }
      return true;
    }
  }
  return false;
}
size_t Nodes::size() const noexcept {
  return nodes.size();
}
Nodes::const_iterator Nodes::begin() const {
  return nodes.cbegin();
}
Nodes::const_iterator Nodes::end() const {
  return nodes.cend();
}
int Nodes::pool_connecting() const {
  int count = 0;
  for (auto& node : nodes) count += node.connection_attempts();
  return count;
}
int Nodes::pool_size() const {
  int count = 0;
  for (auto& node : nodes) count += node.pool_size();
  return count;
}
int32_t Nodes::open_sessions() const {
  return session_cnt;
}
int64_t Nodes::total_sessions() const {
  return session_total;
}
void Nodes::create_session(tcp_ptr client, tcp_ptr outgoing)
{
  int idx = -1;
  if (free_sessions.empty()) {
    idx = sessions.size();
    sessions.emplace_back(*this, idx, client, outgoing);
  } else {
    idx = free_sessions.back();
    new (&sessions[idx]) Session(*this, idx, client, outgoing);
    free_sessions.pop_back();
  }
  session_total++;
  session_cnt++;
  LBOUT("New session %d  (current = %d, total = %ld)\n",
        idx, session_cnt, session_total);
}
Session& Nodes::get_session(int idx)
{
  return sessions.at(idx);
}
void Nodes::close_session(int idx)
{
  auto& session = get_session(idx);
  // disable timeout timer
  Timers::stop(session.timeout_timer);
  session.timeout_timer = Timers::UNUSED_ID;
  // close connections
  if (session.incoming != nullptr) {
    auto conn = std::move(session.incoming);
    conn->reset_callbacks();
    if (conn->is_connected()) conn->close();
  }
  if (session.outgoing != nullptr) {
    auto conn = std::move(session.outgoing);
    conn->reset_callbacks();
    if (conn->is_connected()) conn->close();
  }
  // free session
  free_sessions.push_back(session.self);
  session_cnt--;
  LBOUT("Session %d closed  (total = %d)\n", session.self, session_cnt);
}

Node::Node(netstack_t& stk, net::Socket a, pool_signal_t sig)
  : stack(stk), addr(a), pool_signal(sig)
{
  // periodically connect to node and determine if active
  // however, perform first check immediately
  this->active_timer = Timers::periodic(0s, ACTIVE_CHECK_PERIOD,
  [this] (int) {
    this->perform_active_check();
  });
}
void Node::restart_active_check()
{
  if (this->active_timer == Timers::UNUSED_ID)
  {
    this->active_timer = Timers::periodic(
      ACTIVE_RETRY_PERIOD, ACTIVE_CHECK_PERIOD,
    [this] (int) {
      this->perform_active_check();
    });
  }
}
void Node::perform_active_check()
{
  try {
    this->stack.tcp().connect(this->addr,
    [this] (auto conn) {
      this->active = (conn != nullptr);
      // if we are connected, its alive
      if (conn != nullptr)
      {
        // hopefully put this to good use
        pool.push_back(conn);
        // stop any active check
        this->stop_active_check();
        // signal change in pool
        this->pool_signal();
      }
    });
  } catch (std::exception& e) {
    // do nothing, because might just be eph.ports used up
  }
}
void Node::stop_active_check()
{
  if (this->active_timer != Timers::UNUSED_ID) {
    Timers::stop(this->active_timer);
    this->active_timer = Timers::UNUSED_ID;
  }
}
void Node::connect()
{
  auto outgoing = this->stack.tcp().connect(this->addr);
  // connecting to node atm.
  this->connecting++;
  // retry timer when connect takes too long
  int fail_timer = Timers::oneshot(CONNECT_WAIT_PERIOD,
  [this, outgoing] (int)
  {
    // close connection
    outgoing->abort();
    // no longer connecting
    assert(this->connecting > 0);
    this->connecting --;
    // set as inactive
    this->active = false;
    // restart active check
    this->restart_active_check();
    // signal change in pool
    this->pool_signal();
  });
  // add connection to pool on success, otherwise.. retry
  outgoing->on_connect(
  [this, fail_timer] (auto conn)
  {
    // stop retry timer
    Timers::stop(fail_timer);
    // no longer connecting
    assert(this->connecting > 0);
    this->connecting --;
    // connection may be null, apparently
    if (conn != nullptr && conn->is_connected())
    {
      LBOUT("Connected to %s  (%ld total)\n",
              addr.to_string().c_str(), pool.size());
      this->pool.push_back(conn);
      // stop any active check
      this->stop_active_check();
    }
    else {
      this->perform_active_check();
    }
    // signal change in pool
    this->pool_signal();
  });
}
tcp_ptr Node::get_connection()
{
  while (pool.empty() == false) {
      auto conn = pool.back();
      assert(conn != nullptr);
      pool.pop_back();
      if (conn->is_connected()) return conn;
      else conn->close();
  }
  return nullptr;
}

// use indexing to access Session because std::vector
Session::Session(Nodes& n, int idx, tcp_ptr inc, tcp_ptr out)
    : parent(n), self(idx), incoming(inc), outgoing(out)
{
  this->timeout_timer = Timers::oneshot(INITIAL_SESSION_TIMEOUT,
  [&nodes = n, idx] (int) {
    nodes.close_session(idx);
  });
  incoming->on_read(READQ_PER_CLIENT,
  [&nodes = n, idx] (auto buf, size_t len) mutable {
      auto& session = nodes.get_session(idx);
      session.handle_timeout();
      session.outgoing->write(std::move(buf), len);
  });
  incoming->on_close(
  [&nodes = n, idx] () mutable {
      nodes.close_session(idx);
  });
  outgoing->on_read(READQ_FOR_NODES,
  [&nodes = n, idx] (auto buf, size_t len) mutable {
      auto& session = nodes.get_session(idx);
      session.handle_timeout();
      session.incoming->write(std::move(buf), len);
  });
  outgoing->on_close(
  [&nodes = n, idx] () mutable {
      nodes.close_session(idx);
  });
}
void Session::handle_timeout()
{
  // stop old timer
  Timers::stop(this->timeout_timer);
  // create new timeout
  this->timeout_timer = Timers::oneshot(ROLLING_SESSION_TIMEOUT,
  [&nodes = parent, idx = self] (int) {
    nodes.close_session(idx);
  });
}
<commit_msg>Fix issue with nodes slowly perma offline over time<commit_after>#include "balancer.hpp"

#define LB_VERBOSE 0
#if LB_VERBOSE
#define LBOUT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define LBOUT(fmt, ...) /** **/
#endif

using namespace std::chrono;

Balancer::Balancer(
       netstack_t& incoming, uint16_t in_port,
       netstack_t& outgoing, std::vector<net::Socket> nodelist)
  : netin(incoming), nodes()
{
  for (auto& addr : nodelist) {
    nodes.add_node(outgoing, addr, pool_signal_t{this, &Balancer::handle_queue});
  }

  netin.tcp().listen(in_port,
  [this] (auto conn) {
    if (conn != nullptr) this->incoming(conn);
  });
}

int Balancer::wait_queue() const {
  return queue.size();
}
void Balancer::incoming(tcp_ptr conn)
{
    queue.emplace_back(conn);
    LBOUT("Queueing connection (q=%lu)\n", queue.size());
    // see if LB needs more connections out
    this->handle_connections();
}
void Balancer::handle_queue()
{
  // check waitq
  while (nodes.pool_size() > 0 && queue.empty() == false)
  {
    auto& client = queue.front();
    if (client.conn->is_connected()) {
      // NOTE: explicitly want to copy buffers
      if (nodes.assign(client.conn, client.readq)) {
        queue.pop_front();
      }
    }
  } // waitq check
  // check if we need to create more connections
  this->handle_connections();
}
void Balancer::handle_connections()
{
  int np_connecting = nodes.pool_connecting();
  int estimate = queue.size() - (np_connecting + nodes.pool_size());
  estimate = std::min(estimate, MAX_OUTGOING_ATTEMPTS);
  estimate = std::max(0, estimate - np_connecting);
  if (estimate > 0)
  {
    try {
      // create more outgoing connections
      nodes.create_connections(estimate);
    }
    catch (std::exception& e)
    {
      if (this->rethrow_timer != Timers::UNUSED_ID)
          Timers::stop(this->rethrow_timer);
      // assuming the failure is due to not enough eph. ports
      this->rethrow_timer = Timers::oneshot(CONNECT_THROW_PERIOD,
      [this] (int) {
          this->rethrow_timer = Timers::UNUSED_ID;
          this->handle_connections();
      });
    }
  } // estimate
} // handle_connections()

Waiting::Waiting(tcp_ptr incoming)
  : conn(incoming), total(0)
{
  // queue incoming data from clients not yet
  // assigned to a node
  conn->on_read(READQ_PER_CLIENT,
  [this] (auto buf, size_t len) {
    // prevent buffer bloat attack
    total += len;
    if (total > MAX_READQ_PER_NODE) {
      conn->abort();
    }
    else {
      LBOUT("*** Queued %lu bytes\n", len);
      readq.emplace_back(buf, len);
    }
  });
}

template <typename... Args>
inline void Nodes::add_node(Args&&... args) {
  nodes.emplace_back(std::forward<Args> (args)...);
}
void Nodes::create_connections(int total)
{
  // temporary iterator
  for (int i = 0; i < total; i++)
  {
    // look for next active node up to *size* times
    for (size_t i = 0; i < nodes.size(); i++)
    {
      conn_iterator = (conn_iterator + 1) % nodes.size();
      if (nodes[conn_iterator].is_active()) break;
    }
    // only connect if node is determined active, to prevent
    // building up connect attempts on just one node
    if (nodes[conn_iterator].is_active()) {
      nodes[conn_iterator].connect();
    }
  }
}
bool Nodes::assign(tcp_ptr conn, queue_vector_t& readq)
{
  for (size_t i = 0; i < nodes.size(); i++)
  {
    auto outgoing = nodes[algo_iterator].get_connection();
    // algorithm here //
    algo_iterator = (algo_iterator + 1) % nodes.size();
    // check if connection was retrieved
    if (outgoing != nullptr)
    {
      assert(outgoing->is_connected());
      LBOUT("Assigning client to node %d (%s)\n",
            iterator, outgoing->to_string().c_str());
      this->create_session(conn, outgoing);
      // flush readq
      for (auto& buffer : readq) {
        LBOUT("*** Flushing %lu bytes\n", buffer.second);
        outgoing->write(std::move(buffer.first), buffer.second);
      }
      return true;
    }
  }
  return false;
}
size_t Nodes::size() const noexcept {
  return nodes.size();
}
Nodes::const_iterator Nodes::begin() const {
  return nodes.cbegin();
}
Nodes::const_iterator Nodes::end() const {
  return nodes.cend();
}
int Nodes::pool_connecting() const {
  int count = 0;
  for (auto& node : nodes) count += node.connection_attempts();
  return count;
}
int Nodes::pool_size() const {
  int count = 0;
  for (auto& node : nodes) count += node.pool_size();
  return count;
}
int32_t Nodes::open_sessions() const {
  return session_cnt;
}
int64_t Nodes::total_sessions() const {
  return session_total;
}
void Nodes::create_session(tcp_ptr client, tcp_ptr outgoing)
{
  int idx = -1;
  if (free_sessions.empty()) {
    idx = sessions.size();
    sessions.emplace_back(*this, idx, client, outgoing);
  } else {
    idx = free_sessions.back();
    new (&sessions[idx]) Session(*this, idx, client, outgoing);
    free_sessions.pop_back();
  }
  session_total++;
  session_cnt++;
  LBOUT("New session %d  (current = %d, total = %ld)\n",
        idx, session_cnt, session_total);
}
Session& Nodes::get_session(int idx)
{
  return sessions.at(idx);
}
void Nodes::close_session(int idx)
{
  auto& session = get_session(idx);
  // disable timeout timer
  Timers::stop(session.timeout_timer);
  session.timeout_timer = Timers::UNUSED_ID;
  // close connections
  if (session.incoming != nullptr) {
    auto conn = std::move(session.incoming);
    conn->reset_callbacks();
    if (conn->is_connected()) conn->close();
  }
  if (session.outgoing != nullptr) {
    auto conn = std::move(session.outgoing);
    conn->reset_callbacks();
    if (conn->is_connected()) conn->close();
  }
  // free session
  free_sessions.push_back(session.self);
  session_cnt--;
  LBOUT("Session %d closed  (total = %d)\n", session.self, session_cnt);
}

Node::Node(netstack_t& stk, net::Socket a, pool_signal_t sig)
  : stack(stk), addr(a), pool_signal(sig)
{
  // periodically connect to node and determine if active
  // however, perform first check immediately
  this->active_timer = Timers::periodic(0s, ACTIVE_CHECK_PERIOD,
  [this] (int) {
    this->perform_active_check();
  });
}
void Node::restart_active_check()
{
  if (this->active_timer == Timers::UNUSED_ID)
  {
    this->active_timer = Timers::periodic(
      ACTIVE_RETRY_PERIOD, ACTIVE_CHECK_PERIOD,
    [this] (int) {
      this->perform_active_check();
    });
  }
}
void Node::perform_active_check()
{
  try {
    this->stack.tcp().connect(this->addr,
    [this] (auto conn) {
      this->active = (conn != nullptr);
      // if we are connected, its alive
      if (conn != nullptr)
      {
        // hopefully put this to good use
        pool.push_back(conn);
        // stop any active check
        this->stop_active_check();
        // signal change in pool
        this->pool_signal();
      }
      else {
        // if no periodic check is being done right now,
        // start doing it (after initial delay)
        this->restart_active_check();
      }
    });
  } catch (std::exception& e) {
    // do nothing, because might just be eph.ports used up
  }
}
void Node::stop_active_check()
{
  if (this->active_timer != Timers::UNUSED_ID) {
    Timers::stop(this->active_timer);
    this->active_timer = Timers::UNUSED_ID;
  }
}
void Node::connect()
{
  auto outgoing = this->stack.tcp().connect(this->addr);
  // connecting to node atm.
  this->connecting++;
  // retry timer when connect takes too long
  int fail_timer = Timers::oneshot(CONNECT_WAIT_PERIOD,
  [this, outgoing] (int)
  {
    // close connection
    outgoing->abort();
    // no longer connecting
    assert(this->connecting > 0);
    this->connecting --;
    // set as inactive
    this->active = false;
    // restart active check
    this->restart_active_check();
    // signal change in pool
    this->pool_signal();
  });
  // add connection to pool on success, otherwise.. retry
  outgoing->on_connect(
  [this, fail_timer] (auto conn)
  {
    // stop retry timer
    Timers::stop(fail_timer);
    // no longer connecting
    assert(this->connecting > 0);
    this->connecting --;
    // connection may be null, apparently
    if (conn != nullptr && conn->is_connected())
    {
      LBOUT("Connected to %s  (%ld total)\n",
              addr.to_string().c_str(), pool.size());
      this->pool.push_back(conn);
      // stop any active check
      this->stop_active_check();
      // signal change in pool
      this->pool_signal();
    }
    else {
      this->restart_active_check();
    }
  });
}
tcp_ptr Node::get_connection()
{
  while (pool.empty() == false) {
      auto conn = pool.back();
      assert(conn != nullptr);
      pool.pop_back();
      if (conn->is_connected()) return conn;
      else conn->close();
  }
  return nullptr;
}

// use indexing to access Session because std::vector
Session::Session(Nodes& n, int idx, tcp_ptr inc, tcp_ptr out)
    : parent(n), self(idx), incoming(inc), outgoing(out)
{
  this->timeout_timer = Timers::oneshot(INITIAL_SESSION_TIMEOUT,
  [&nodes = n, idx] (int) {
    nodes.close_session(idx);
  });
  incoming->on_read(READQ_PER_CLIENT,
  [&nodes = n, idx] (auto buf, size_t len) mutable {
      auto& session = nodes.get_session(idx);
      session.handle_timeout();
      session.outgoing->write(std::move(buf), len);
  });
  incoming->on_close(
  [&nodes = n, idx] () mutable {
      nodes.close_session(idx);
  });
  outgoing->on_read(READQ_FOR_NODES,
  [&nodes = n, idx] (auto buf, size_t len) mutable {
      auto& session = nodes.get_session(idx);
      session.handle_timeout();
      session.incoming->write(std::move(buf), len);
  });
  outgoing->on_close(
  [&nodes = n, idx] () mutable {
      nodes.close_session(idx);
  });
}
void Session::handle_timeout()
{
  // stop old timer
  Timers::stop(this->timeout_timer);
  // create new timeout
  this->timeout_timer = Timers::oneshot(ROLLING_SESSION_TIMEOUT,
  [&nodes = parent, idx = self] (int) {
    nodes.close_session(idx);
  });
}
<|endoftext|>


<commit_before>#include "Map.h"

#include "../../../../texture/ImageDecompression.h"

#include "Arrow.h"

Map::Map(GLuint program, const GraphicsObjectManager& graphicsObjectManager) : HUDobject_Animated(program, graphicsObjectManager)
{
	EventHandler::addCursorPosHook(this);
	EventHandler::addScrollHook(this);

	GLenum format;
	unsigned char* imageData = extractImageFrom7zFile("../../Source/map.7z", &m_originalWidth, &m_originalHeight, &format);

	glGenTextures(1, &m_textureObject);
	glBindTexture(GL_TEXTURE_2D, m_textureObject);

	glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, m_originalWidth, m_originalHeight);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_originalWidth, m_originalHeight, format, GL_UNSIGNED_BYTE, imageData);
	freeImageData(imageData);

	//glGenerateMipmap(GL_TEXTURE_2D);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	m_zoomLevel = ZoomLevel();

	this->setCoords({ 0.0f, 0.0f }, (GLfloat)m_originalWidth, (GLfloat)m_originalHeight, 0);

	m_arrows.push_back(new Arrow(graphicsObjectManager, *this, { 0.03f, 0.06f }, { 0.03f, 0.2f }));
	float mapAspectRatio = 3712.0f / 3333;
	m_arrows.push_back(new Arrow(graphicsObjectManager, *this, { 0.06f, 0.06f * mapAspectRatio }, { 0.15f,  0.15f * mapAspectRatio }));
	m_arrows.push_back(new Arrow(graphicsObjectManager, *this, { 0.06f, 0.03f }, { 0.27f, 0.03f }));
}

Map::~Map()
{
	EventHandler::removeCursorPosHook(this);
	EventHandler::removeScrollHook(this);

	for (auto arrow : m_arrows) delete arrow;
}

void Map::cursorPosCallback(const InputManager& input)
{
	if (input.getMouse().m_isLeftMouseButtonDown)
	{
		CursorPos cursorPos = input.getMouse().getCursorPos();
		move({ cursorPos.deltaX, cursorPos.deltaY }, 0);
	}
}

void Map::scrollCallback(float xOffset, float yOffset, const InputManager& input)
{
	CursorPos cursorPos = input.getMouse().getCursorPos();

	ZoomLevel oldZoomLevel = m_zoomLevel;
	if (oldZoomLevel == m_zoomLevel.offsetLevel((int)yOffset))
		return;

	GLfloat currentWidth = getWidth();
	GLfloat newWidth = m_originalWidth * m_zoomLevel.getPercentage();

	zoom(newWidth / currentWidth, 1.0f / 4.0f, cursorPos);
}

void Map::graphicsUpdate(GLuint program, const GraphicsObjectManager& graphicsObjectManager)
{
	glBindTexture(GL_TEXTURE_2D, m_textureObject);

	HUDobject_Animated::graphicsUpdate(program, graphicsObjectManager);
	HUDobject_Dynamic::graphicsUpdate(program, graphicsObjectManager);

	for (Arrow* arrow : m_arrows)
		arrow->graphicsUpdate(graphicsObjectManager);
}
<commit_msg>Implemented Arrow::updatePosition()<commit_after>#include "Map.h"

#include "../../../../texture/ImageDecompression.h"

#include "Arrow.h"

Map::Map(GLuint program, const GraphicsObjectManager& graphicsObjectManager) : HUDobject_Animated(program, graphicsObjectManager)
{
	EventHandler::addCursorPosHook(this);
	EventHandler::addScrollHook(this);

	GLenum format;
	unsigned char* imageData = extractImageFrom7zFile("../../Source/map.7z", &m_originalWidth, &m_originalHeight, &format);

	glGenTextures(1, &m_textureObject);
	glBindTexture(GL_TEXTURE_2D, m_textureObject);

	glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, m_originalWidth, m_originalHeight);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_originalWidth, m_originalHeight, format, GL_UNSIGNED_BYTE, imageData);
	freeImageData(imageData);

	//glGenerateMipmap(GL_TEXTURE_2D);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	m_zoomLevel = ZoomLevel();

	this->setCoords({ 0.0f, 0.0f }, (GLfloat)m_originalWidth, (GLfloat)m_originalHeight, 0);

	m_arrows.push_back(new Arrow(graphicsObjectManager, *this, { 0.03f, 0.06f }, { 0.03f, 0.2f }));
	float mapAspectRatio = 3712.0f / 3333;
	m_arrows.push_back(new Arrow(graphicsObjectManager, *this, { 0.06f, 0.06f * mapAspectRatio }, { 0.15f,  0.15f * mapAspectRatio }));
	m_arrows.push_back(new Arrow(graphicsObjectManager, *this, { 0.06f, 0.03f }, { 0.27f, 0.03f }));
}

Map::~Map()
{
	EventHandler::removeCursorPosHook(this);
	EventHandler::removeScrollHook(this);

	for (auto arrow : m_arrows) delete arrow;
}

void Map::cursorPosCallback(const InputManager& input)
{
	if (input.getMouse().m_isLeftMouseButtonDown)
	{
		CursorPos cursorPos = input.getMouse().getCursorPos();
		move({ cursorPos.deltaX, cursorPos.deltaY }, 0);
	}
}

void Map::scrollCallback(float xOffset, float yOffset, const InputManager& input)
{
	CursorPos cursorPos = input.getMouse().getCursorPos();

	ZoomLevel oldZoomLevel = m_zoomLevel;
	if (oldZoomLevel == m_zoomLevel.offsetLevel((int)yOffset))
		return;

	GLfloat currentWidth = getWidth();
	GLfloat newWidth = m_originalWidth * m_zoomLevel.getPercentage();

	zoom(newWidth / currentWidth, 1.0f / 4.0f, cursorPos);
}

void Map::graphicsUpdate(GLuint program, const GraphicsObjectManager& graphicsObjectManager)
{
	glBindTexture(GL_TEXTURE_2D, m_textureObject);

	HUDobject_Animated::graphicsUpdate(program, graphicsObjectManager);

	if (m_dirtyFlag)
	{
		for (Arrow* arrow : m_arrows)
			arrow->updatePosition(*this);
	}

	HUDobject_Dynamic::graphicsUpdate(program, graphicsObjectManager);

	for (Arrow* arrow : m_arrows)
		arrow->graphicsUpdate(graphicsObjectManager);
}
<|endoftext|>


<commit_before>/*
	Copyright (C) 1998, 1999 by Nathaniel 'NooTe' Saint Martin
	Copyright (C) 1998, 1999 by Jorrit Tyberghein
	Written by Nathaniel 'NooTe' Saint Martin

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Library General Public
	License as published by the Free Software Foundation; either
	version 2 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Library General Public License for more details.

	You should have received a copy of the GNU Library General Public
	License along with this library; if not, write to the Free
	Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

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

#include "cssysdef.h"
#include "csutil/sysfunc.h"
#include "iutil/plugin.h"
#include "iutil/cfgfile.h"
#include "iutil/event.h"
#include "iutil/eventq.h"
#include "iutil/objreg.h"
#include "isound/driver.h"
#include "isound/data.h"
#include "iutil/eventh.h"
#include "iutil/comp.h"
#include "iutil/virtclk.h"
#include "iutil/cmdline.h"
#include "ivaria/reporter.h"

#include "srdrcom.h"
#include "../common/slstn.h"
#include "srdrsrc.h"
#include "sndhdl.h"

CS_IMPLEMENT_PLUGIN

SCF_IMPLEMENT_FACTORY (csSoundRenderSoftware)

SCF_IMPLEMENT_IBASE(csSoundRenderSoftware)
	SCF_IMPLEMENTS_INTERFACE(iSoundRender)
	SCF_IMPLEMENTS_EMBEDDED_INTERFACE(iComponent)
SCF_IMPLEMENT_IBASE_END;

SCF_IMPLEMENT_EMBEDDED_IBASE (csSoundRenderSoftware::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_IBASE (csSoundRenderSoftware::EventHandler)
  SCF_IMPLEMENTS_INTERFACE (iEventHandler)
SCF_IMPLEMENT_IBASE_END

csSoundRenderSoftware::csSoundRenderSoftware(iBase* piBase) : Listener(0)
{
  SCF_CONSTRUCT_IBASE(piBase);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiComponent);
  scfiEventHandler = 0;
  object_reg = 0;
  Listener = 0;
  memory = 0;
  memorysize = 0;
  ActivateMixing = false;
  owning = downing = false;
  data = csCondition::Create ();
  mixing = csMutex::Create (true);
}

void csSoundRenderSoftware::Report (int severity, const char* msg, ...)
{
  va_list arg;
  va_start (arg, msg);
  csRef<iReporter> rep (CS_QUERY_REGISTRY (object_reg, iReporter));
  if (rep)
    rep->ReportV (severity, "crystalspace.sound.software", msg, arg);
  else
  {
    csPrintfV (msg, arg);
    csPrintf ("\n");
  }
  va_end (arg);
}

bool csSoundRenderSoftware::Initialize (iObjectRegistry *r)
{
  // copy the system pointer
  object_reg = r;

  // read the config file
  Config.AddConfig(object_reg, "/config/sound.cfg");

  // check for optional sound driver fro the commandline
  csRef<iCommandLineParser> cmdline (CS_QUERY_REGISTRY (r, iCommandLineParser));
  const char *drv = cmdline->GetOption ("sounddriver");
  if (!drv)
  {
    // load the sound driver plug-in
#ifdef CS_SOUND_DRIVER
    drv = CS_SOUND_DRIVER;   // "crystalspace.sound.driver.xxx"
#else
    drv = "crystalspace.sound.driver.null";
#endif
    drv = Config->GetStr ("Sound.Driver", drv);
  }

  csRef<iPluginManager> plugin_mgr (
  	CS_QUERY_REGISTRY (object_reg, iPluginManager));
  SoundDriver = CS_LOAD_PLUGIN (plugin_mgr, drv, iSoundDriver);
  if (!SoundDriver)
  {
    Report (CS_REPORTER_SEVERITY_ERROR,
      "csSoundRenderSoftware: Failed to load sound driver: %s", drv);
    return false;
  }

  // set event callback
  if (!scfiEventHandler)
    scfiEventHandler = new EventHandler (this);
  csRef<iEventQueue> q (CS_QUERY_REGISTRY(object_reg, iEventQueue));
  if (q != 0)
    q->RegisterListener(scfiEventHandler,
      CSMASK_Command | CSMASK_Broadcast | CSMASK_Nothing);

  return true;
}

csSoundRenderSoftware::~csSoundRenderSoftware()
{
  if (scfiEventHandler)
  {
    csRef<iEventQueue> q (CS_QUERY_REGISTRY(object_reg, iEventQueue));
    if (q != 0)
      q->RemoveListener (scfiEventHandler);
    scfiEventHandler->DecRef ();
  }
  Close();
  SCF_DESTRUCT_EMBEDDED_IBASE(scfiComponent);
  SCF_DESTRUCT_IBASE();
}

bool csSoundRenderSoftware::Open()
{
  Report (CS_REPORTER_SEVERITY_NOTIFY, "Software Sound Renderer selected");
  CS_ASSERT (Config != 0);

  if (!SoundDriver) return false;

  SoundDriver->Open (this,
    Config->GetInt("Sound.Software.Frequency", 22050),
    Config->GetBool("Sound.Software.16Bits", true),
    Config->GetBool("Sound.Software.Stereo", true));

  Volume = Config->GetFloat("Sound.Volume", 1.0);
  if (Volume>1) Volume = 1;
  if (Volume<0) Volume = 0;

  Listener = new csSoundListener ();
  ActivateMixing = true;
  LoadFormat.Freq = getFrequency();
  LoadFormat.Bits = is16Bits() ? 16 : 8;
  LoadFormat.Channels = -1;

  Report (CS_REPORTER_SEVERITY_NOTIFY, "  Playing %d Hz, %d bits, %s",
    getFrequency(), (is16Bits())?16:8, (isStereo())?"Stereo":"Mono");
  Report (CS_REPORTER_SEVERITY_NOTIFY, "  Volume: %g", Volume);

  csTicks et, ct;
  csRef<iVirtualClock> vc (CS_QUERY_REGISTRY (object_reg, iVirtualClock));

  et = vc->GetElapsedTicks ();
  ct = vc->GetCurrentTicks ();
  LastTime = ct;

  if (SoundDriver->ThreadAware ())
  {
    mixing->LockWait ();
    bRunning = true;
    mixer = csThread::Create (new MixerRunnable (this));
    mixer->Start ();
    mixing->Release ();
  }
  return true;
}

void csSoundRenderSoftware::Close()
{
  bRunning = false;
  data->Signal (true);
  mixing->LockWait ();
  owning = true;
  downing = true;
  ActivateMixing = false;
  if (SoundDriver)
  {
    SoundDriver->Close ();
    SoundDriver = 0;
  }

  if (Listener)
  {
    Listener->DecRef();
    Listener = 0;
  }

  while (Sources.Length()>0)
    Sources.Get(0)->Stop();

  while (SoundHandles.Length()>0)
  {
    csSoundHandleSoftware *hdl = SoundHandles.Pop();
    hdl->Unregister();
    hdl->DecRef();
  }
  owning = false;
  downing = false;
  mixing->Release ();
}

csPtr<iSoundHandle> csSoundRenderSoftware::RegisterSound(iSoundData *snd)
{
  // convert the sound
  if (!snd->Initialize(&LoadFormat)) return 0;

  // create the sound handle
  csSoundHandleSoftware *hdl = new csSoundHandleSoftware(this, snd);
  SoundHandles.Push(hdl);
  hdl->IncRef ();	// Prevent smart pointer release.
  return csPtr<iSoundHandle> (hdl);
}

void csSoundRenderSoftware::UnregisterSound(iSoundHandle *snd)
{
  int n = SoundHandles.Find((csSoundHandleSoftware*)snd);
  if (n != -1)
  {
    if (owning || mixing->LockWait ()) // dont remove while we mix
    {
      csSoundHandleSoftware *hdl = (csSoundHandleSoftware *)snd;
      SoundHandles.DeleteIndex (n);
      hdl->Unregister();
      hdl->DecRef();

      if (!owning) mixing->Release ();
    }
  }
}

iSoundListener *csSoundRenderSoftware::GetListener()
{
  return Listener;
}

bool csSoundRenderSoftware::is16Bits()
{
  return SoundDriver->Is16Bits();
}

bool csSoundRenderSoftware::isStereo()
{
  return SoundDriver->IsStereo();
}

int csSoundRenderSoftware::getFrequency()
{
  return SoundDriver->GetFrequency();
}

void csSoundRenderSoftware::SetVolume(float vol)
{
  Volume = vol;
}

float csSoundRenderSoftware::GetVolume()
{
  return Volume;
}

void csSoundRenderSoftware::AddSource(csSoundSourceSoftware *src)
{
  Sources.Push(src);
  src->IncRef();
  data->Signal (true);
}

void csSoundRenderSoftware::RemoveSource(csSoundSourceSoftware *src)
{
  if (downing || mixing->LockWait ()) // dont remove while we mix
  {
    if (!downing) owning = true;
    int n=Sources.Find(src);
    if (n!=-1)
    {
      Sources.DeleteIndex (n);
      src->DecRef();
    }
    if (!downing)
    {
      owning = false;
      mixing->Release ();
    }
  }
}

void csSoundRenderSoftware::MixingFunction()
{
  size_t i;

  // look if this function is activated
  if (!ActivateMixing) return;

  // test if we have a sound driver
  if(!SoundDriver) return;

  // Get a mixing lock.  Mutex is recursive.
  mixing->LockWait ();

  // if no sources exist, there may be an optimized way to handle this
  if (Sources.Length()==0 && SoundDriver->IsHandleVoidSound())
  {
    mixing->Release();
    return;
  }

  // lock sound memory
  SoundDriver->LockMemory(&memory, &memorysize);
  if(!memory || memorysize<1)
  {
    mixing->Release();
    return;
  }

  // clear the buffer
  if (is16Bits()) memset(memory,0,memorysize);
  else memset(memory,128,memorysize);

  // prepare and play all sources
  for (i=0;i<Sources.Length();i++)
  {
    csSoundSourceSoftware *src=Sources.Get(i);
    src->Prepare(Volume);
    src->AddToBufferStatic(memory, memorysize);
    if (!src->IsActive())
    {
      Sources.DeleteIndex (i);
      src->DecRef ();
      i--;
    }
  }

  /* Do not update the sound handles. Right now the source advances
   *  the sound data stream.  The default handle UpdateCount() function
   *  will also advance the stream causing the sound to skip and play
   *  twice as fast if the stream is started.
   */
/*
  // update sound handles
   long NumSamples = memorysize / (is16Bits()?2:1) / (isStereo()?2:1);
   for (i=0;i<SoundHandles.Length();i++) {
    csSoundHandleSoftware *hdl = SoundHandles.Get(i);
    hdl->UpdateCount(NumSamples);
  }
*/
  SoundDriver->UnlockMemory();
  mixing->Release();
}

bool csSoundRenderSoftware::HandleEvent (iEvent &e)
{
  if (e.Type == csevCommand || e.Type == csevBroadcast) {
    switch (e.Command.Code) {
    case cscmdPreProcess:
      Update();
      break;
    case cscmdSystemOpen:
      Open();
      break;
    case cscmdSystemClose:
      Close();
      break;
    }
  }
  return false;
}

void csSoundRenderSoftware::Update()
{
  // update sound if the sound driver doesn't do it
  if(!SoundDriver->IsBackground()) MixingFunction();
}

void csSoundRenderSoftware::ThreadedMix ()
{
  while (bRunning)
  {
    mixing->LockWait ();
    data->Wait (mixing);
    bool bRelock = false;
    while (bRunning && Sources.Length() != 0)
    {
      if (bRelock) mixing->LockWait ();
      MixingFunction ();
      mixing->Release ();
      bRelock = true;
    }
    if (!bRelock) mixing->Release ();
  }
}
<commit_msg>Release the renderer mutex while closing the driver to avoid a potential deadlock.<commit_after>/*
	Copyright (C) 1998, 1999 by Nathaniel 'NooTe' Saint Martin
	Copyright (C) 1998, 1999 by Jorrit Tyberghein
	Written by Nathaniel 'NooTe' Saint Martin

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Library General Public
	License as published by the Free Software Foundation; either
	version 2 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Library General Public License for more details.

	You should have received a copy of the GNU Library General Public
	License along with this library; if not, write to the Free
	Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

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

#include "cssysdef.h"
#include "csutil/sysfunc.h"
#include "iutil/plugin.h"
#include "iutil/cfgfile.h"
#include "iutil/event.h"
#include "iutil/eventq.h"
#include "iutil/objreg.h"
#include "isound/driver.h"
#include "isound/data.h"
#include "iutil/eventh.h"
#include "iutil/comp.h"
#include "iutil/virtclk.h"
#include "iutil/cmdline.h"
#include "ivaria/reporter.h"

#include "srdrcom.h"
#include "../common/slstn.h"
#include "srdrsrc.h"
#include "sndhdl.h"

CS_IMPLEMENT_PLUGIN

SCF_IMPLEMENT_FACTORY (csSoundRenderSoftware)

SCF_IMPLEMENT_IBASE(csSoundRenderSoftware)
	SCF_IMPLEMENTS_INTERFACE(iSoundRender)
	SCF_IMPLEMENTS_EMBEDDED_INTERFACE(iComponent)
SCF_IMPLEMENT_IBASE_END;

SCF_IMPLEMENT_EMBEDDED_IBASE (csSoundRenderSoftware::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_IBASE (csSoundRenderSoftware::EventHandler)
  SCF_IMPLEMENTS_INTERFACE (iEventHandler)
SCF_IMPLEMENT_IBASE_END

csSoundRenderSoftware::csSoundRenderSoftware(iBase* piBase) : Listener(0)
{
  SCF_CONSTRUCT_IBASE(piBase);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiComponent);
  scfiEventHandler = 0;
  object_reg = 0;
  Listener = 0;
  memory = 0;
  memorysize = 0;
  ActivateMixing = false;
  owning = downing = false;
  data = csCondition::Create ();
  mixing = csMutex::Create (true);
}

void csSoundRenderSoftware::Report (int severity, const char* msg, ...)
{
  va_list arg;
  va_start (arg, msg);
  csRef<iReporter> rep (CS_QUERY_REGISTRY (object_reg, iReporter));
  if (rep)
    rep->ReportV (severity, "crystalspace.sound.software", msg, arg);
  else
  {
    csPrintfV (msg, arg);
    csPrintf ("\n");
  }
  va_end (arg);
}

bool csSoundRenderSoftware::Initialize (iObjectRegistry *r)
{
  // copy the system pointer
  object_reg = r;

  // read the config file
  Config.AddConfig(object_reg, "/config/sound.cfg");

  // check for optional sound driver fro the commandline
  csRef<iCommandLineParser> cmdline (CS_QUERY_REGISTRY (r, iCommandLineParser));
  const char *drv = cmdline->GetOption ("sounddriver");
  if (!drv)
  {
    // load the sound driver plug-in
#ifdef CS_SOUND_DRIVER
    drv = CS_SOUND_DRIVER;   // "crystalspace.sound.driver.xxx"
#else
    drv = "crystalspace.sound.driver.null";
#endif
    drv = Config->GetStr ("Sound.Driver", drv);
  }

  csRef<iPluginManager> plugin_mgr (
  	CS_QUERY_REGISTRY (object_reg, iPluginManager));
  SoundDriver = CS_LOAD_PLUGIN (plugin_mgr, drv, iSoundDriver);
  if (!SoundDriver)
  {
    Report (CS_REPORTER_SEVERITY_ERROR,
      "csSoundRenderSoftware: Failed to load sound driver: %s", drv);
    return false;
  }

  // set event callback
  if (!scfiEventHandler)
    scfiEventHandler = new EventHandler (this);
  csRef<iEventQueue> q (CS_QUERY_REGISTRY(object_reg, iEventQueue));
  if (q != 0)
    q->RegisterListener(scfiEventHandler,
      CSMASK_Command | CSMASK_Broadcast | CSMASK_Nothing);

  return true;
}

csSoundRenderSoftware::~csSoundRenderSoftware()
{
  if (scfiEventHandler)
  {
    csRef<iEventQueue> q (CS_QUERY_REGISTRY(object_reg, iEventQueue));
    if (q != 0)
      q->RemoveListener (scfiEventHandler);
    scfiEventHandler->DecRef ();
  }
  Close();
  SCF_DESTRUCT_EMBEDDED_IBASE(scfiComponent);
  SCF_DESTRUCT_IBASE();
}

bool csSoundRenderSoftware::Open()
{
  Report (CS_REPORTER_SEVERITY_NOTIFY, "Software Sound Renderer selected");
  CS_ASSERT (Config != 0);

  if (!SoundDriver) return false;

  SoundDriver->Open (this,
    Config->GetInt("Sound.Software.Frequency", 22050),
    Config->GetBool("Sound.Software.16Bits", true),
    Config->GetBool("Sound.Software.Stereo", true));

  Volume = Config->GetFloat("Sound.Volume", 1.0);
  if (Volume>1) Volume = 1;
  if (Volume<0) Volume = 0;

  Listener = new csSoundListener ();
  ActivateMixing = true;
  LoadFormat.Freq = getFrequency();
  LoadFormat.Bits = is16Bits() ? 16 : 8;
  LoadFormat.Channels = -1;

  Report (CS_REPORTER_SEVERITY_NOTIFY, "  Playing %d Hz, %d bits, %s",
    getFrequency(), (is16Bits())?16:8, (isStereo())?"Stereo":"Mono");
  Report (CS_REPORTER_SEVERITY_NOTIFY, "  Volume: %g", Volume);

  csTicks et, ct;
  csRef<iVirtualClock> vc (CS_QUERY_REGISTRY (object_reg, iVirtualClock));

  et = vc->GetElapsedTicks ();
  ct = vc->GetCurrentTicks ();
  LastTime = ct;

  if (SoundDriver->ThreadAware ())
  {
    mixing->LockWait ();
    bRunning = true;
    mixer = csThread::Create (new MixerRunnable (this));
    mixer->Start ();
    mixing->Release ();
  }
  return true;
}

void csSoundRenderSoftware::Close()
{
  bRunning = false;
  data->Signal (true);
  mixing->LockWait ();
  owning = true;
  downing = true;
  ActivateMixing = false;

  // Must release the lock while we close the driver
  mixing->Release ();

  if (SoundDriver)
  {
    SoundDriver->Close ();
    SoundDriver = 0;
  }

  mixing->LockWait ();
  if (Listener)
  {
    Listener->DecRef();
    Listener = 0;
  }

  while (Sources.Length()>0)
    Sources.Get(0)->Stop();

  while (SoundHandles.Length()>0)
  {
    csSoundHandleSoftware *hdl = SoundHandles.Pop();
    hdl->Unregister();
    hdl->DecRef();
  }
  owning = false;
  downing = false;
  mixing->Release ();
}

csPtr<iSoundHandle> csSoundRenderSoftware::RegisterSound(iSoundData *snd)
{
  // convert the sound
  if (!snd->Initialize(&LoadFormat)) return 0;

  // create the sound handle
  csSoundHandleSoftware *hdl = new csSoundHandleSoftware(this, snd);
  SoundHandles.Push(hdl);
  hdl->IncRef ();	// Prevent smart pointer release.
  return csPtr<iSoundHandle> (hdl);
}

void csSoundRenderSoftware::UnregisterSound(iSoundHandle *snd)
{
  int n = SoundHandles.Find((csSoundHandleSoftware*)snd);
  if (n != -1)
  {
    if (owning || mixing->LockWait ()) // dont remove while we mix
    {
      csSoundHandleSoftware *hdl = (csSoundHandleSoftware *)snd;
      SoundHandles.DeleteIndex (n);
      hdl->Unregister();
      hdl->DecRef();

      if (!owning) mixing->Release ();
    }
  }
}

iSoundListener *csSoundRenderSoftware::GetListener()
{
  return Listener;
}

bool csSoundRenderSoftware::is16Bits()
{
  return SoundDriver->Is16Bits();
}

bool csSoundRenderSoftware::isStereo()
{
  return SoundDriver->IsStereo();
}

int csSoundRenderSoftware::getFrequency()
{
  return SoundDriver->GetFrequency();
}

void csSoundRenderSoftware::SetVolume(float vol)
{
  Volume = vol;
}

float csSoundRenderSoftware::GetVolume()
{
  return Volume;
}

void csSoundRenderSoftware::AddSource(csSoundSourceSoftware *src)
{
  Sources.Push(src);
  src->IncRef();
  data->Signal (true);
}

void csSoundRenderSoftware::RemoveSource(csSoundSourceSoftware *src)
{
  if (downing || mixing->LockWait ()) // dont remove while we mix
  {
    if (!downing) owning = true;
    int n=Sources.Find(src);
    if (n!=-1)
    {
      Sources.DeleteIndex (n);
      src->DecRef();
    }
    if (!downing)
    {
      owning = false;
      mixing->Release ();
    }
  }
}

void csSoundRenderSoftware::MixingFunction()
{
  size_t i;

  // look if this function is activated
  if (!ActivateMixing) return;

  // test if we have a sound driver
  if(!SoundDriver) return;

  // Get a mixing lock.  Mutex is recursive.
  mixing->LockWait ();

  // if no sources exist, there may be an optimized way to handle this
  if (Sources.Length()==0 && SoundDriver->IsHandleVoidSound())
  {
    mixing->Release();
    return;
  }

  // lock sound memory
  SoundDriver->LockMemory(&memory, &memorysize);
  if(!memory || memorysize<1)
  {
    mixing->Release();
    return;
  }

  // clear the buffer
  if (is16Bits()) memset(memory,0,memorysize);
  else memset(memory,128,memorysize);

  // prepare and play all sources
  for (i=0;i<Sources.Length();i++)
  {
    csSoundSourceSoftware *src=Sources.Get(i);
    src->Prepare(Volume);
    src->AddToBufferStatic(memory, memorysize);
    if (!src->IsActive())
    {
      Sources.DeleteIndex (i);
      src->DecRef ();
      i--;
    }
  }

  /* Do not update the sound handles. Right now the source advances
   *  the sound data stream.  The default handle UpdateCount() function
   *  will also advance the stream causing the sound to skip and play
   *  twice as fast if the stream is started.
   */
/*
  // update sound handles
   long NumSamples = memorysize / (is16Bits()?2:1) / (isStereo()?2:1);
   for (i=0;i<SoundHandles.Length();i++) {
    csSoundHandleSoftware *hdl = SoundHandles.Get(i);
    hdl->UpdateCount(NumSamples);
  }
*/
  SoundDriver->UnlockMemory();
  mixing->Release();
}

bool csSoundRenderSoftware::HandleEvent (iEvent &e)
{
  if (e.Type == csevCommand || e.Type == csevBroadcast) {
    switch (e.Command.Code) {
    case cscmdPreProcess:
      Update();
      break;
    case cscmdSystemOpen:
      Open();
      break;
    case cscmdSystemClose:
      Close();
      break;
    }
  }
  return false;
}

void csSoundRenderSoftware::Update()
{
  // update sound if the sound driver doesn't do it
  if(!SoundDriver->IsBackground()) MixingFunction();
}

void csSoundRenderSoftware::ThreadedMix ()
{
  while (bRunning)
  {
    mixing->LockWait ();
    data->Wait (mixing);
    bool bRelock = false;
    while (bRunning && Sources.Length() != 0)
    {
      if (bRelock) mixing->LockWait ();
      MixingFunction ();
      mixing->Release ();
      bRelock = true;
    }
    if (!bRelock) mixing->Release ();
  }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: window3.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: kz $ $Date: 2005-01-13 18:06:55 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#define _SV_WINDOW_CXX

#ifndef _SV_SVSYS_HXX
#include <svsys.h>
#endif

#ifndef _SV_WINDOW_H
#include <window.h>
#endif
#ifndef _SV_WINDOW_HXX
#include <window.hxx>
#endif
#ifndef _SV_WAITOBJ_HXX
#include <waitobj.hxx>
#endif

#ifndef _SV_SALGDI_HXX
#include <salgdi.hxx>
#endif
#ifndef _SV_NATIVEWIDGETS_HXX
#include <salnativewidgets.hxx>
#endif
#ifndef _SV_SALCTRLHANDLE_HXX
#include <salctrlhandle.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

using namespace rtl;

// -----------------------------------------------------------------------
// These functions are mainly passthrough functions that allow access to
// the SalFrame behind a Window object for native widget rendering purposes.
// -----------------------------------------------------------------------

void Window::ImplInitSalControlHandle()
{
    // create SalControlHandle on demand
    // not needed for ordinary windows
    // TODO: move creation to SalGraphics
    //if( !ImplGetWinData()->mpSalControlHandle )
    //    ImplGetWinData()->mpSalControlHandle = new SalControlHandle;
}

// -----------------------------------------------------------------------

BOOL Window::IsNativeControlSupported( ControlType nType, ControlPart nPart )
{
    if( !IsNativeWidgetEnabled() )
        return FALSE;

    if ( !mpGraphics )
        if ( !ImplGetGraphics() )
            return FALSE;

    return( mpGraphics->IsNativeControlSupported(nType, nPart) );
}

// -----------------------------------------------------------------------

BOOL Window::HitTestNativeControl( ControlType nType,
                              ControlPart nPart,
                              const Region& rControlRegion,
                              const Point& aPos,
                              BOOL& rIsInside )
{
    if( !IsNativeWidgetEnabled() )
        return FALSE;

    if ( !mpGraphics )
        if ( !ImplGetGraphics() )
            return FALSE;

    ImplInitSalControlHandle();
    return( mpGraphics->HitTestNativeControl(nType, nPart, rControlRegion, aPos, *ImplGetWinData()->mpSalControlHandle, rIsInside, this ) );
}

// -----------------------------------------------------------------------

BOOL Window::DrawNativeControl( ControlType nType,
                            ControlPart nPart,
                            const Region& rControlRegion,
                            ControlState nState,
                            const ImplControlValue& aValue,
                            OUString aCaption )
{
    if( !IsNativeWidgetEnabled() )
        return FALSE;

    /*
    if( !IsInPaint() && IsPaintTransparent() )
    {
        // only required if called directly (ie, we're not in Paint() ):
        // force redraw (Paint()) for transparent controls
        // to trigger a repaint of the background
        Region aClipRgn( GetClipRegion() );
        if( !rControlRegion.IsEmpty() )
            aClipRgn.Intersect( rControlRegion );
        Invalidate( aClipRgn, INVALIDATE_UPDATE );
        return TRUE;
    }
    */

    ImplInitSalControlHandle();

    // make sure the current clip region is initialized correctly
    if ( !mpGraphics )
        if ( !ImplGetGraphics() )
            return FALSE;

    if ( mbInitClipRegion )
        ImplInitClipRegion();
    if ( mbOutputClipped )
        return TRUE;

    if ( mbInitLineColor )
        ImplInitLineColor();
    if ( mbInitFillColor )
        ImplInitFillColor();

    // Convert the coordinates from relative to Window-absolute, so we draw
    // in the correct place in platform code
    Point aWinOffs;
    aWinOffs = OutputToScreenPixel( aWinOffs );
    Region screenRegion( rControlRegion );
    screenRegion.Move( aWinOffs.X(), aWinOffs.Y());

    Region aTestRegion( GetActiveClipRegion() );
    aTestRegion.Intersect( rControlRegion );
    if( aTestRegion == rControlRegion )
        nState |= CTRL_CACHING_ALLOWED;   // control is not clipped, caching allowed

    return( mpGraphics->DrawNativeControl(nType, nPart, screenRegion, nState, aValue, *ImplGetWinData()->mpSalControlHandle, aCaption, this ) );
}

// -----------------------------------------------------------------------

BOOL Window::DrawNativeControlText(ControlType nType,
                            ControlPart nPart,
                            const Region& rControlRegion,
                            ControlState nState,
                            const ImplControlValue& aValue,
                            OUString aCaption )
{
    if( !IsNativeWidgetEnabled() )
        return FALSE;

    ImplInitSalControlHandle();

    // make sure the current clip region is initialized correctly
    if ( !mpGraphics )
        if ( !ImplGetGraphics() )
            return false;

    if ( mbInitClipRegion )
        ImplInitClipRegion();
    if ( mbOutputClipped )
        return true;

    if ( mbInitLineColor )
        ImplInitLineColor();
    if ( mbInitFillColor )
        ImplInitFillColor();

    // Convert the coordinates from relative to Window-absolute, so we draw
    // in the correct place in platform code
    Point aWinOffs;
    aWinOffs = OutputToScreenPixel( aWinOffs );
    Region screenRegion( rControlRegion );
    screenRegion.Move( aWinOffs.X(), aWinOffs.Y());

    return( mpGraphics->DrawNativeControlText(nType, nPart, screenRegion, nState, aValue, *ImplGetWinData()->mpSalControlHandle, aCaption, this ) );
}

// -----------------------------------------------------------------------

BOOL Window::GetNativeControlRegion(  ControlType nType,
                                ControlPart nPart,
                                const Region& rControlRegion,
                                ControlState nState,
                                const ImplControlValue& aValue,
                                OUString aCaption,
                                Region &rNativeBoundingRegion,
                                Region &rNativeContentRegion )
{
    if( !IsNativeWidgetEnabled() )
        return FALSE;

    if ( !mpGraphics )
        if ( !ImplGetGraphics() )
            return FALSE;

    ImplInitSalControlHandle();
    return( mpGraphics->GetNativeControlRegion(nType, nPart, rControlRegion, nState, aValue,
                                *ImplGetWinData()->mpSalControlHandle, aCaption, rNativeBoundingRegion,
                                rNativeContentRegion, this ) );
}

// -----------------------------------------------------------------------

WaitObject::~WaitObject()
{
    if ( mpWindow )
        mpWindow->LeaveWait();
}
<commit_msg>INTEGRATION: CWS ooo19126 (1.4.258); FILE MERGED 2005/09/05 14:45:19 rt 1.4.258.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: window3.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 12:33:18 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#define _SV_WINDOW_CXX

#ifndef _SV_SVSYS_HXX
#include <svsys.h>
#endif

#ifndef _SV_WINDOW_H
#include <window.h>
#endif
#ifndef _SV_WINDOW_HXX
#include <window.hxx>
#endif
#ifndef _SV_WAITOBJ_HXX
#include <waitobj.hxx>
#endif

#ifndef _SV_SALGDI_HXX
#include <salgdi.hxx>
#endif
#ifndef _SV_NATIVEWIDGETS_HXX
#include <salnativewidgets.hxx>
#endif
#ifndef _SV_SALCTRLHANDLE_HXX
#include <salctrlhandle.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

using namespace rtl;

// -----------------------------------------------------------------------
// These functions are mainly passthrough functions that allow access to
// the SalFrame behind a Window object for native widget rendering purposes.
// -----------------------------------------------------------------------

void Window::ImplInitSalControlHandle()
{
    // create SalControlHandle on demand
    // not needed for ordinary windows
    // TODO: move creation to SalGraphics
    //if( !ImplGetWinData()->mpSalControlHandle )
    //    ImplGetWinData()->mpSalControlHandle = new SalControlHandle;
}

// -----------------------------------------------------------------------

BOOL Window::IsNativeControlSupported( ControlType nType, ControlPart nPart )
{
    if( !IsNativeWidgetEnabled() )
        return FALSE;

    if ( !mpGraphics )
        if ( !ImplGetGraphics() )
            return FALSE;

    return( mpGraphics->IsNativeControlSupported(nType, nPart) );
}

// -----------------------------------------------------------------------

BOOL Window::HitTestNativeControl( ControlType nType,
                              ControlPart nPart,
                              const Region& rControlRegion,
                              const Point& aPos,
                              BOOL& rIsInside )
{
    if( !IsNativeWidgetEnabled() )
        return FALSE;

    if ( !mpGraphics )
        if ( !ImplGetGraphics() )
            return FALSE;

    ImplInitSalControlHandle();
    return( mpGraphics->HitTestNativeControl(nType, nPart, rControlRegion, aPos, *ImplGetWinData()->mpSalControlHandle, rIsInside, this ) );
}

// -----------------------------------------------------------------------

BOOL Window::DrawNativeControl( ControlType nType,
                            ControlPart nPart,
                            const Region& rControlRegion,
                            ControlState nState,
                            const ImplControlValue& aValue,
                            OUString aCaption )
{
    if( !IsNativeWidgetEnabled() )
        return FALSE;

    /*
    if( !IsInPaint() && IsPaintTransparent() )
    {
        // only required if called directly (ie, we're not in Paint() ):
        // force redraw (Paint()) for transparent controls
        // to trigger a repaint of the background
        Region aClipRgn( GetClipRegion() );
        if( !rControlRegion.IsEmpty() )
            aClipRgn.Intersect( rControlRegion );
        Invalidate( aClipRgn, INVALIDATE_UPDATE );
        return TRUE;
    }
    */

    ImplInitSalControlHandle();

    // make sure the current clip region is initialized correctly
    if ( !mpGraphics )
        if ( !ImplGetGraphics() )
            return FALSE;

    if ( mbInitClipRegion )
        ImplInitClipRegion();
    if ( mbOutputClipped )
        return TRUE;

    if ( mbInitLineColor )
        ImplInitLineColor();
    if ( mbInitFillColor )
        ImplInitFillColor();

    // Convert the coordinates from relative to Window-absolute, so we draw
    // in the correct place in platform code
    Point aWinOffs;
    aWinOffs = OutputToScreenPixel( aWinOffs );
    Region screenRegion( rControlRegion );
    screenRegion.Move( aWinOffs.X(), aWinOffs.Y());

    Region aTestRegion( GetActiveClipRegion() );
    aTestRegion.Intersect( rControlRegion );
    if( aTestRegion == rControlRegion )
        nState |= CTRL_CACHING_ALLOWED;   // control is not clipped, caching allowed

    return( mpGraphics->DrawNativeControl(nType, nPart, screenRegion, nState, aValue, *ImplGetWinData()->mpSalControlHandle, aCaption, this ) );
}

// -----------------------------------------------------------------------

BOOL Window::DrawNativeControlText(ControlType nType,
                            ControlPart nPart,
                            const Region& rControlRegion,
                            ControlState nState,
                            const ImplControlValue& aValue,
                            OUString aCaption )
{
    if( !IsNativeWidgetEnabled() )
        return FALSE;

    ImplInitSalControlHandle();

    // make sure the current clip region is initialized correctly
    if ( !mpGraphics )
        if ( !ImplGetGraphics() )
            return false;

    if ( mbInitClipRegion )
        ImplInitClipRegion();
    if ( mbOutputClipped )
        return true;

    if ( mbInitLineColor )
        ImplInitLineColor();
    if ( mbInitFillColor )
        ImplInitFillColor();

    // Convert the coordinates from relative to Window-absolute, so we draw
    // in the correct place in platform code
    Point aWinOffs;
    aWinOffs = OutputToScreenPixel( aWinOffs );
    Region screenRegion( rControlRegion );
    screenRegion.Move( aWinOffs.X(), aWinOffs.Y());

    return( mpGraphics->DrawNativeControlText(nType, nPart, screenRegion, nState, aValue, *ImplGetWinData()->mpSalControlHandle, aCaption, this ) );
}

// -----------------------------------------------------------------------

BOOL Window::GetNativeControlRegion(  ControlType nType,
                                ControlPart nPart,
                                const Region& rControlRegion,
                                ControlState nState,
                                const ImplControlValue& aValue,
                                OUString aCaption,
                                Region &rNativeBoundingRegion,
                                Region &rNativeContentRegion )
{
    if( !IsNativeWidgetEnabled() )
        return FALSE;

    if ( !mpGraphics )
        if ( !ImplGetGraphics() )
            return FALSE;

    ImplInitSalControlHandle();
    return( mpGraphics->GetNativeControlRegion(nType, nPart, rControlRegion, nState, aValue,
                                *ImplGetWinData()->mpSalControlHandle, aCaption, rNativeBoundingRegion,
                                rNativeContentRegion, this ) );
}

// -----------------------------------------------------------------------

WaitObject::~WaitObject()
{
    if ( mpWindow )
        mpWindow->LeaveWait();
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/bootstrap.h"

#include "include/dart_api.h"

#include "vm/bootstrap_natives.h"
#include "vm/class_finalizer.h"
#include "vm/compiler.h"
#include "vm/dart_api_impl.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/symbols.h"

namespace dart {

#define INIT_LIBRARY(index, name, source, patch)                               \
  { index,                                                                     \
    "dart:"#name, source,                                                      \
    "dart:"#name"-patch", patch }                                              \

typedef struct {
  ObjectStore::BootstrapLibraryId index_;
  const char* uri_;
  const char** source_paths_;
  const char* patch_uri_;
  const char** patch_paths_;
} bootstrap_lib_props;

enum {
  kPathsUriOffset = 0,
  kPathsFileOffset = 1,
  kPathsSourceOffset = 2,
  kPathsEntryLength = 3
};

static bootstrap_lib_props bootstrap_libraries[] = {
  INIT_LIBRARY(ObjectStore::kCore,
               core,
               Bootstrap::core_source_paths_,
               Bootstrap::core_patch_paths_),
  INIT_LIBRARY(ObjectStore::kAsync,
               async,
               Bootstrap::async_source_paths_,
               Bootstrap::async_patch_paths_),
  INIT_LIBRARY(ObjectStore::kConvert,
               convert,
               Bootstrap::convert_source_paths_,
               Bootstrap::convert_patch_paths_),
  INIT_LIBRARY(ObjectStore::kCollection,
               collection,
               Bootstrap::collection_source_paths_,
               Bootstrap::collection_patch_paths_),
  INIT_LIBRARY(ObjectStore::kDeveloper,
               developer,
               Bootstrap::developer_source_paths_,
               Bootstrap::developer_patch_paths_),
  INIT_LIBRARY(ObjectStore::kInternal,
               _internal,
               Bootstrap::_internal_source_paths_,
               Bootstrap::_internal_patch_paths_),
  INIT_LIBRARY(ObjectStore::kIsolate,
               isolate,
               Bootstrap::isolate_source_paths_,
               Bootstrap::isolate_patch_paths_),
  INIT_LIBRARY(ObjectStore::kMath,
               math,
               Bootstrap::math_source_paths_,
               Bootstrap::math_patch_paths_),
  INIT_LIBRARY(ObjectStore::kMirrors,
               mirrors,
               Bootstrap::mirrors_source_paths_,
               Bootstrap::mirrors_patch_paths_),
  INIT_LIBRARY(ObjectStore::kProfiler,
               profiler,
               Bootstrap::profiler_source_paths_,
               NULL),
  INIT_LIBRARY(ObjectStore::kTypedData,
               typed_data,
               Bootstrap::typed_data_source_paths_,
               Bootstrap::typed_data_patch_paths_),
  INIT_LIBRARY(ObjectStore::kVMService,
               _vmservice,
               Bootstrap::_vmservice_source_paths_,
               Bootstrap::_vmservice_patch_paths_),
  { ObjectStore::kNone, NULL, NULL, NULL, NULL }
};

static RawString* GetLibrarySource(const Library& lib,
                                   const String& uri,
                                   bool patch) {
  // First check if this is a valid bootstrap library and find it's index
  // in the 'bootstrap_libraries' table above.
  intptr_t index;
  const String& lib_uri = String::Handle(lib.url());
  for (index = 0;
       bootstrap_libraries[index].index_ != ObjectStore::kNone;
       ++index) {
    if (lib_uri.Equals(bootstrap_libraries[index].uri_)) {
      break;
    }
  }
  if (bootstrap_libraries[index].index_ == ObjectStore::kNone) {
    return String::null();  // Library is not a bootstrap library.
  }

  // Try to read the source using the path specified for the uri.
  const char** source_paths = patch ?
      bootstrap_libraries[index].patch_paths_ :
      bootstrap_libraries[index].source_paths_;
  if (source_paths == NULL) {
    return String::null();  // No path mapping information exists for library.
  }
  const char* source_path = NULL;
  const char* source_data = NULL;
  for (intptr_t i = 0; source_paths[i] != NULL; i += kPathsEntryLength) {
    if (uri.Equals(source_paths[i + kPathsUriOffset])) {
      source_path = source_paths[i + kPathsFileOffset];
      source_data = source_paths[i + kPathsSourceOffset];
      break;
    }
  }
  if ((source_path == NULL) && (source_data == NULL)) {
    return String::null();  // Uri does not exist in path mapping information.
  }

  const uint8_t* utf8_array = NULL;
  intptr_t file_length = -1;

  Dart_FileOpenCallback file_open = Isolate::file_open_callback();
  Dart_FileReadCallback file_read = Isolate::file_read_callback();
  Dart_FileCloseCallback file_close = Isolate::file_close_callback();
  if ((file_open != NULL) && (file_read != NULL) && (file_close != NULL)) {
    // Try to open and read the file.
    void* stream = (*file_open)(source_path, false);
    if (stream != NULL) {
      (*file_read)(&utf8_array, &file_length, stream);
      (*file_close)(stream);
    }
  }
  if (file_length == -1) {
    if (source_data != NULL) {
      file_length = strlen(source_data);
      utf8_array = reinterpret_cast<const uint8_t*>(source_data);
    } else {
      return String::null();
    }
  }
  ASSERT(utf8_array != NULL);
  ASSERT(file_length >= 0);
  return String::FromUTF8(utf8_array, file_length);
}

static RawError* Compile(const Library& library, const Script& script) {
  bool update_lib_status = (script.kind() == RawScript::kScriptTag ||
                            script.kind() == RawScript::kLibraryTag);
  if (update_lib_status) {
    library.SetLoadInProgress();
  }
  const Error& error = Error::Handle(Compiler::Compile(library, script));
  if (update_lib_status) {
    if (error.IsNull()) {
      library.SetLoaded();
    } else {
      // Compilation errors are not Dart instances, so just mark the library
      // as having failed to load without providing an error instance.
      library.SetLoadError(Object::null_instance());
    }
  }
  return error.raw();
}

static Dart_Handle LoadPartSource(Thread* thread,
                                  const Library& lib,
                                  const String& uri) {
  Zone* zone = thread->zone();
  const String& part_source = String::Handle(
      zone, GetLibrarySource(lib, uri, false));
  const String& lib_uri = String::Handle(zone, lib.url());
  if (part_source.IsNull()) {
    return Api::NewError("Unable to read part file '%s' of library '%s'",
                         uri.ToCString(), lib_uri.ToCString());
  }

  // Prepend the library URI to form a unique script URI for the part.
  const Array& strings = Array::Handle(zone, Array::New(3));
  strings.SetAt(0, lib_uri);
  strings.SetAt(1, Symbols::Slash());
  strings.SetAt(2, uri);
  const String& part_uri = String::Handle(zone, String::ConcatAll(strings));

  // Create a script object and compile the part.
  const Script& part_script = Script::Handle(
      zone, Script::New(part_uri, part_source, RawScript::kSourceTag));
  const Error& error = Error::Handle(zone, Compile(lib, part_script));
  return Api::NewHandle(thread, error.raw());
}

static Dart_Handle BootstrapLibraryTagHandler(Dart_LibraryTag tag,
                                              Dart_Handle library,
                                              Dart_Handle uri) {
  Thread* thread = Thread::Current();
  Zone* zone = thread->zone();
  // This handler calls into the VM directly and does not use the Dart
  // API so we transition back to VM.
  TransitionNativeToVM transition(thread);
  if (!Dart_IsLibrary(library)) {
    return Api::NewError("not a library");
  }
  if (!Dart_IsString(uri)) {
    return Api::NewError("uri is not a string");
  }
  if (tag == Dart_kCanonicalizeUrl) {
    // In the bootstrap loader we do not try and do any canonicalization.
    return uri;
  }
  const String& uri_str = Api::UnwrapStringHandle(zone, uri);
  ASSERT(!uri_str.IsNull());
  if (tag == Dart_kImportTag) {
    // We expect the core bootstrap libraries to only import other
    // core bootstrap libraries.
    // We have precreated all the bootstrap library objects hence
    // we do not expect to be called back with the tag set to kImportTag.
    // The bootstrap process explicitly loads all the libraries one by one.
    return Api::NewError("Invalid import of '%s' in a bootstrap library",
                         uri_str.ToCString());
  }
  ASSERT(tag == Dart_kSourceTag);
  const Library& lib = Api::UnwrapLibraryHandle(zone, library);
  ASSERT(!lib.IsNull());
  return LoadPartSource(thread, lib, uri_str);
}

static RawError* LoadPatchFiles(Zone* zone,
                                const Library& lib,
                                const String& patch_uri,
                                const char** patch_files) {
  String& patch_file_uri = String::Handle(zone);
  String& source = String::Handle(zone);
  Script& script = Script::Handle(zone);
  Error& error = Error::Handle(zone);
  const Array& strings = Array::Handle(zone, Array::New(3));
  strings.SetAt(0, patch_uri);
  strings.SetAt(1, Symbols::Slash());
  for (intptr_t j = 0; patch_files[j] != NULL; j += kPathsEntryLength) {
    patch_file_uri = String::New(patch_files[j + kPathsUriOffset]);
    source = GetLibrarySource(lib, patch_file_uri, true);
    if (source.IsNull()) {
      const String& message = String::Handle(
          String::NewFormatted("Unable to find dart patch source for %s",
                               patch_file_uri.ToCString()));
      return ApiError::New(message);
    }
    // Prepend the patch library URI to form a unique script URI for the patch.
    strings.SetAt(2, patch_file_uri);
    patch_file_uri = String::ConcatAll(strings);
    script = Script::New(patch_file_uri, source, RawScript::kPatchTag);
    error = lib.Patch(script);
    if (!error.IsNull()) {
      return error.raw();
    }
  }
  return Error::null();
}

RawError* Bootstrap::LoadandCompileScripts() {
  Thread* thread = Thread::Current();
  Isolate* isolate = thread->isolate();
  Zone* zone = thread->zone();
  String& uri = String::Handle(zone);
  String& patch_uri = String::Handle(zone);
  String& source = String::Handle(zone);
  Script& script = Script::Handle(zone);
  Library& lib = Library::Handle(zone);
  Error& error = Error::Handle(zone);
  Dart_LibraryTagHandler saved_tag_handler = isolate->library_tag_handler();

  // Set the library tag handler for the isolate to the bootstrap
  // library tag handler so that we can load all the bootstrap libraries.
  isolate->set_library_tag_handler(BootstrapLibraryTagHandler);

  HANDLESCOPE(thread);

  // Create library objects for all the bootstrap libraries.
  for (intptr_t i = 0;
       bootstrap_libraries[i].index_ != ObjectStore::kNone;
       ++i) {
#ifdef PRODUCT
    if (bootstrap_libraries[i].index_ == ObjectStore::kMirrors) {
      continue;
    }
#endif  // !PRODUCT
    uri = Symbols::New(bootstrap_libraries[i].uri_);
    lib = Library::LookupLibrary(uri);
    if (lib.IsNull()) {
      lib = Library::NewLibraryHelper(uri, false);
      lib.SetLoadRequested();
      lib.Register();
    }
    isolate->object_store()->set_bootstrap_library(
        bootstrap_libraries[i].index_, lib);
  }

  // Load, compile and patch bootstrap libraries.
  for (intptr_t i = 0;
       bootstrap_libraries[i].index_ != ObjectStore::kNone;
       ++i) {
#ifdef PRODUCT
    if (bootstrap_libraries[i].index_ == ObjectStore::kMirrors) {
      continue;
    }
#endif  // PRODUCT
    uri = Symbols::New(bootstrap_libraries[i].uri_);
    lib = Library::LookupLibrary(uri);
    ASSERT(!lib.IsNull());
    source = GetLibrarySource(lib, uri, false);
    if (source.IsNull()) {
      const String& message = String::Handle(
          String::NewFormatted("Unable to find dart source for %s",
                               uri.ToCString()));
      error ^= ApiError::New(message);
      break;
    }
    script = Script::New(uri, source, RawScript::kLibraryTag);
    error = Compile(lib, script);
    if (!error.IsNull()) {
      break;
    }
    // If a patch exists, load and patch the script.
    if (bootstrap_libraries[i].patch_paths_ != NULL) {
      patch_uri = Symbols::New(bootstrap_libraries[i].patch_uri_);
      error = LoadPatchFiles(zone,
                             lib,
                             patch_uri,
                             bootstrap_libraries[i].patch_paths_);
      if (!error.IsNull()) {
        break;
      }
    }
  }
  if (error.IsNull()) {
    SetupNativeResolver();
    ClassFinalizer::ProcessPendingClasses();

    // Eagerly compile the _Closure class as it is the class of all closure
    // instances. This allows us to just finalize function types
    // without going through the hoops of trying to compile their scope class.
    const Class& cls =
        Class::Handle(zone, isolate->object_store()->closure_class());
    Compiler::CompileClass(cls);
  }

  // Restore the library tag handler for the isolate.
  isolate->set_library_tag_handler(saved_tag_handler);

  return error.raw();
}

}  // namespace dart
<commit_msg>Eagerly finalize bool class, before bool constants are used in the compiler.<commit_after>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/bootstrap.h"

#include "include/dart_api.h"

#include "vm/bootstrap_natives.h"
#include "vm/class_finalizer.h"
#include "vm/compiler.h"
#include "vm/dart_api_impl.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/symbols.h"

namespace dart {

#define INIT_LIBRARY(index, name, source, patch)                               \
  { index,                                                                     \
    "dart:"#name, source,                                                      \
    "dart:"#name"-patch", patch }                                              \

typedef struct {
  ObjectStore::BootstrapLibraryId index_;
  const char* uri_;
  const char** source_paths_;
  const char* patch_uri_;
  const char** patch_paths_;
} bootstrap_lib_props;

enum {
  kPathsUriOffset = 0,
  kPathsFileOffset = 1,
  kPathsSourceOffset = 2,
  kPathsEntryLength = 3
};

static bootstrap_lib_props bootstrap_libraries[] = {
  INIT_LIBRARY(ObjectStore::kCore,
               core,
               Bootstrap::core_source_paths_,
               Bootstrap::core_patch_paths_),
  INIT_LIBRARY(ObjectStore::kAsync,
               async,
               Bootstrap::async_source_paths_,
               Bootstrap::async_patch_paths_),
  INIT_LIBRARY(ObjectStore::kConvert,
               convert,
               Bootstrap::convert_source_paths_,
               Bootstrap::convert_patch_paths_),
  INIT_LIBRARY(ObjectStore::kCollection,
               collection,
               Bootstrap::collection_source_paths_,
               Bootstrap::collection_patch_paths_),
  INIT_LIBRARY(ObjectStore::kDeveloper,
               developer,
               Bootstrap::developer_source_paths_,
               Bootstrap::developer_patch_paths_),
  INIT_LIBRARY(ObjectStore::kInternal,
               _internal,
               Bootstrap::_internal_source_paths_,
               Bootstrap::_internal_patch_paths_),
  INIT_LIBRARY(ObjectStore::kIsolate,
               isolate,
               Bootstrap::isolate_source_paths_,
               Bootstrap::isolate_patch_paths_),
  INIT_LIBRARY(ObjectStore::kMath,
               math,
               Bootstrap::math_source_paths_,
               Bootstrap::math_patch_paths_),
  INIT_LIBRARY(ObjectStore::kMirrors,
               mirrors,
               Bootstrap::mirrors_source_paths_,
               Bootstrap::mirrors_patch_paths_),
  INIT_LIBRARY(ObjectStore::kProfiler,
               profiler,
               Bootstrap::profiler_source_paths_,
               NULL),
  INIT_LIBRARY(ObjectStore::kTypedData,
               typed_data,
               Bootstrap::typed_data_source_paths_,
               Bootstrap::typed_data_patch_paths_),
  INIT_LIBRARY(ObjectStore::kVMService,
               _vmservice,
               Bootstrap::_vmservice_source_paths_,
               Bootstrap::_vmservice_patch_paths_),
  { ObjectStore::kNone, NULL, NULL, NULL, NULL }
};

static RawString* GetLibrarySource(const Library& lib,
                                   const String& uri,
                                   bool patch) {
  // First check if this is a valid bootstrap library and find it's index
  // in the 'bootstrap_libraries' table above.
  intptr_t index;
  const String& lib_uri = String::Handle(lib.url());
  for (index = 0;
       bootstrap_libraries[index].index_ != ObjectStore::kNone;
       ++index) {
    if (lib_uri.Equals(bootstrap_libraries[index].uri_)) {
      break;
    }
  }
  if (bootstrap_libraries[index].index_ == ObjectStore::kNone) {
    return String::null();  // Library is not a bootstrap library.
  }

  // Try to read the source using the path specified for the uri.
  const char** source_paths = patch ?
      bootstrap_libraries[index].patch_paths_ :
      bootstrap_libraries[index].source_paths_;
  if (source_paths == NULL) {
    return String::null();  // No path mapping information exists for library.
  }
  const char* source_path = NULL;
  const char* source_data = NULL;
  for (intptr_t i = 0; source_paths[i] != NULL; i += kPathsEntryLength) {
    if (uri.Equals(source_paths[i + kPathsUriOffset])) {
      source_path = source_paths[i + kPathsFileOffset];
      source_data = source_paths[i + kPathsSourceOffset];
      break;
    }
  }
  if ((source_path == NULL) && (source_data == NULL)) {
    return String::null();  // Uri does not exist in path mapping information.
  }

  const uint8_t* utf8_array = NULL;
  intptr_t file_length = -1;

  Dart_FileOpenCallback file_open = Isolate::file_open_callback();
  Dart_FileReadCallback file_read = Isolate::file_read_callback();
  Dart_FileCloseCallback file_close = Isolate::file_close_callback();
  if ((file_open != NULL) && (file_read != NULL) && (file_close != NULL)) {
    // Try to open and read the file.
    void* stream = (*file_open)(source_path, false);
    if (stream != NULL) {
      (*file_read)(&utf8_array, &file_length, stream);
      (*file_close)(stream);
    }
  }
  if (file_length == -1) {
    if (source_data != NULL) {
      file_length = strlen(source_data);
      utf8_array = reinterpret_cast<const uint8_t*>(source_data);
    } else {
      return String::null();
    }
  }
  ASSERT(utf8_array != NULL);
  ASSERT(file_length >= 0);
  return String::FromUTF8(utf8_array, file_length);
}

static RawError* Compile(const Library& library, const Script& script) {
  bool update_lib_status = (script.kind() == RawScript::kScriptTag ||
                            script.kind() == RawScript::kLibraryTag);
  if (update_lib_status) {
    library.SetLoadInProgress();
  }
  const Error& error = Error::Handle(Compiler::Compile(library, script));
  if (update_lib_status) {
    if (error.IsNull()) {
      library.SetLoaded();
    } else {
      // Compilation errors are not Dart instances, so just mark the library
      // as having failed to load without providing an error instance.
      library.SetLoadError(Object::null_instance());
    }
  }
  return error.raw();
}

static Dart_Handle LoadPartSource(Thread* thread,
                                  const Library& lib,
                                  const String& uri) {
  Zone* zone = thread->zone();
  const String& part_source = String::Handle(
      zone, GetLibrarySource(lib, uri, false));
  const String& lib_uri = String::Handle(zone, lib.url());
  if (part_source.IsNull()) {
    return Api::NewError("Unable to read part file '%s' of library '%s'",
                         uri.ToCString(), lib_uri.ToCString());
  }

  // Prepend the library URI to form a unique script URI for the part.
  const Array& strings = Array::Handle(zone, Array::New(3));
  strings.SetAt(0, lib_uri);
  strings.SetAt(1, Symbols::Slash());
  strings.SetAt(2, uri);
  const String& part_uri = String::Handle(zone, String::ConcatAll(strings));

  // Create a script object and compile the part.
  const Script& part_script = Script::Handle(
      zone, Script::New(part_uri, part_source, RawScript::kSourceTag));
  const Error& error = Error::Handle(zone, Compile(lib, part_script));
  return Api::NewHandle(thread, error.raw());
}

static Dart_Handle BootstrapLibraryTagHandler(Dart_LibraryTag tag,
                                              Dart_Handle library,
                                              Dart_Handle uri) {
  Thread* thread = Thread::Current();
  Zone* zone = thread->zone();
  // This handler calls into the VM directly and does not use the Dart
  // API so we transition back to VM.
  TransitionNativeToVM transition(thread);
  if (!Dart_IsLibrary(library)) {
    return Api::NewError("not a library");
  }
  if (!Dart_IsString(uri)) {
    return Api::NewError("uri is not a string");
  }
  if (tag == Dart_kCanonicalizeUrl) {
    // In the bootstrap loader we do not try and do any canonicalization.
    return uri;
  }
  const String& uri_str = Api::UnwrapStringHandle(zone, uri);
  ASSERT(!uri_str.IsNull());
  if (tag == Dart_kImportTag) {
    // We expect the core bootstrap libraries to only import other
    // core bootstrap libraries.
    // We have precreated all the bootstrap library objects hence
    // we do not expect to be called back with the tag set to kImportTag.
    // The bootstrap process explicitly loads all the libraries one by one.
    return Api::NewError("Invalid import of '%s' in a bootstrap library",
                         uri_str.ToCString());
  }
  ASSERT(tag == Dart_kSourceTag);
  const Library& lib = Api::UnwrapLibraryHandle(zone, library);
  ASSERT(!lib.IsNull());
  return LoadPartSource(thread, lib, uri_str);
}

static RawError* LoadPatchFiles(Zone* zone,
                                const Library& lib,
                                const String& patch_uri,
                                const char** patch_files) {
  String& patch_file_uri = String::Handle(zone);
  String& source = String::Handle(zone);
  Script& script = Script::Handle(zone);
  Error& error = Error::Handle(zone);
  const Array& strings = Array::Handle(zone, Array::New(3));
  strings.SetAt(0, patch_uri);
  strings.SetAt(1, Symbols::Slash());
  for (intptr_t j = 0; patch_files[j] != NULL; j += kPathsEntryLength) {
    patch_file_uri = String::New(patch_files[j + kPathsUriOffset]);
    source = GetLibrarySource(lib, patch_file_uri, true);
    if (source.IsNull()) {
      const String& message = String::Handle(
          String::NewFormatted("Unable to find dart patch source for %s",
                               patch_file_uri.ToCString()));
      return ApiError::New(message);
    }
    // Prepend the patch library URI to form a unique script URI for the patch.
    strings.SetAt(2, patch_file_uri);
    patch_file_uri = String::ConcatAll(strings);
    script = Script::New(patch_file_uri, source, RawScript::kPatchTag);
    error = lib.Patch(script);
    if (!error.IsNull()) {
      return error.raw();
    }
  }
  return Error::null();
}

RawError* Bootstrap::LoadandCompileScripts() {
  Thread* thread = Thread::Current();
  Isolate* isolate = thread->isolate();
  Zone* zone = thread->zone();
  String& uri = String::Handle(zone);
  String& patch_uri = String::Handle(zone);
  String& source = String::Handle(zone);
  Script& script = Script::Handle(zone);
  Library& lib = Library::Handle(zone);
  Error& error = Error::Handle(zone);
  Dart_LibraryTagHandler saved_tag_handler = isolate->library_tag_handler();

  // Set the library tag handler for the isolate to the bootstrap
  // library tag handler so that we can load all the bootstrap libraries.
  isolate->set_library_tag_handler(BootstrapLibraryTagHandler);

  HANDLESCOPE(thread);

  // Create library objects for all the bootstrap libraries.
  for (intptr_t i = 0;
       bootstrap_libraries[i].index_ != ObjectStore::kNone;
       ++i) {
#ifdef PRODUCT
    if (bootstrap_libraries[i].index_ == ObjectStore::kMirrors) {
      continue;
    }
#endif  // !PRODUCT
    uri = Symbols::New(bootstrap_libraries[i].uri_);
    lib = Library::LookupLibrary(uri);
    if (lib.IsNull()) {
      lib = Library::NewLibraryHelper(uri, false);
      lib.SetLoadRequested();
      lib.Register();
    }
    isolate->object_store()->set_bootstrap_library(
        bootstrap_libraries[i].index_, lib);
  }

  // Load, compile and patch bootstrap libraries.
  for (intptr_t i = 0;
       bootstrap_libraries[i].index_ != ObjectStore::kNone;
       ++i) {
#ifdef PRODUCT
    if (bootstrap_libraries[i].index_ == ObjectStore::kMirrors) {
      continue;
    }
#endif  // PRODUCT
    uri = Symbols::New(bootstrap_libraries[i].uri_);
    lib = Library::LookupLibrary(uri);
    ASSERT(!lib.IsNull());
    source = GetLibrarySource(lib, uri, false);
    if (source.IsNull()) {
      const String& message = String::Handle(
          String::NewFormatted("Unable to find dart source for %s",
                               uri.ToCString()));
      error ^= ApiError::New(message);
      break;
    }
    script = Script::New(uri, source, RawScript::kLibraryTag);
    error = Compile(lib, script);
    if (!error.IsNull()) {
      break;
    }
    // If a patch exists, load and patch the script.
    if (bootstrap_libraries[i].patch_paths_ != NULL) {
      patch_uri = Symbols::New(bootstrap_libraries[i].patch_uri_);
      error = LoadPatchFiles(zone,
                             lib,
                             patch_uri,
                             bootstrap_libraries[i].patch_paths_);
      if (!error.IsNull()) {
        break;
      }
    }
  }
  if (error.IsNull()) {
    SetupNativeResolver();
    ClassFinalizer::ProcessPendingClasses();

    // Eagerly compile the _Closure class as it is the class of all closure
    // instances. This allows us to just finalize function types
    // without going through the hoops of trying to compile their scope class.
    Class& cls =
        Class::Handle(zone, isolate->object_store()->closure_class());
    Compiler::CompileClass(cls);
    // Eagerly compile Bool class, bool constants are used from within compiler.
    cls = isolate->object_store()->bool_class();
    Compiler::CompileClass(cls);
  }

  // Restore the library tag handler for the isolate.
  isolate->set_library_tag_handler(saved_tag_handler);

  return error.raw();
}

}  // namespace dart
<|endoftext|>