<commit_before>//===-- MainLoop.cpp --------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Config/config.h"

#include "lldb/Host/MainLoop.h"
#include "lldb/Utility/Error.h"
#include <algorithm>
#include <cassert>
#include <cerrno>
#include <csignal>
#include <vector>
#include <time.h>

#if HAVE_SYS_EVENT_H
#include <sys/event.h>
#elif defined(LLVM_ON_WIN32)
#include <winsock2.h>
#else
#include <poll.h>
#endif

#ifdef LLVM_ON_WIN32
#define POLL WSAPoll
#else
#define POLL poll
#endif

#if SIGNAL_POLLING_UNSUPPORTED
#ifdef LLVM_ON_WIN32
typedef int sigset_t;
#endif

int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts,
          const sigset_t *) {
  int timeout =
      (timeout_ts == nullptr)
          ? -1
          : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
  return POLL(fds, nfds, timeout);
}

#endif

using namespace lldb;
using namespace lldb_private;

static sig_atomic_t g_signal_flags[NSIG];

static void SignalHandler(int signo, siginfo_t *info, void *) {
  assert(signo < NSIG);
  g_signal_flags[signo] = 1;
}

MainLoop::~MainLoop() {
  assert(m_read_fds.size() == 0);
  assert(m_signals.size() == 0);
}

MainLoop::ReadHandleUP
MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
                                  const Callback &callback, Error &error) {
#ifdef LLVM_ON_WIN32
  if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) {
    error.SetErrorString("MainLoop: non-socket types unsupported on Windows");
    return nullptr;
  }
#endif
  if (!object_sp || !object_sp->IsValid()) {
    error.SetErrorString("IO object is not valid.");
    return nullptr;
  }

  const bool inserted =
      m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
  if (!inserted) {
    error.SetErrorStringWithFormat("File descriptor %d already monitored.",
                                   object_sp->GetWaitableHandle());
    return nullptr;
  }

  return CreateReadHandle(object_sp);
}

// We shall block the signal, then install the signal handler. The signal will
// be unblocked in
// the Run() function to check for signal delivery.
MainLoop::SignalHandleUP
MainLoop::RegisterSignal(int signo, const Callback &callback,
                              Error &error) {
#ifdef SIGNAL_POLLING_UNSUPPORTED
  error.SetErrorString("Signal polling is not supported on this platform.");
  return nullptr;
#else
  if (m_signals.find(signo) != m_signals.end()) {
    error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
    return nullptr;
  }

  SignalInfo info;
  info.callback = callback;
  struct sigaction new_action;
  new_action.sa_sigaction = &SignalHandler;
  new_action.sa_flags = SA_SIGINFO;
  sigemptyset(&new_action.sa_mask);
  sigaddset(&new_action.sa_mask, signo);

  sigset_t old_set;
  if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) {
    error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n",
                                   ret);
    return nullptr;
  }

  info.was_blocked = sigismember(&old_set, signo);
  if (sigaction(signo, &new_action, &info.old_action) == -1) {
    error.SetErrorToErrno();
    if (!info.was_blocked)
      pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr);
    return nullptr;
  }

  m_signals.insert({signo, info});
  g_signal_flags[signo] = 0;

  return SignalHandleUP(new SignalHandle(*this, signo));
#endif
}

void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
  bool erased = m_read_fds.erase(handle);
  UNUSED_IF_ASSERT_DISABLED(erased);
  assert(erased);
}

void MainLoop::UnregisterSignal(int signo) {
#if SIGNAL_POLLING_UNSUPPORTED
  Error("Signal polling is not supported on this platform.");
#else
  // We undo the actions of RegisterSignal on a best-effort basis.
  auto it = m_signals.find(signo);
  assert(it != m_signals.end());

  sigaction(signo, &it->second.old_action, nullptr);

  sigset_t set;
  sigemptyset(&set);
  sigaddset(&set, signo);
  pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set,
                  nullptr);

  m_signals.erase(it);
#endif
}

Error MainLoop::Run() {
  std::vector<int> signals;
  m_terminate_request = false;
  signals.reserve(m_signals.size());

#if HAVE_SYS_EVENT_H
  int queue_id = kqueue();
  if (queue_id < 0)
    Error("kqueue failed with error %d\n", queue_id);

  std::vector<struct kevent> events;
  events.reserve(m_read_fds.size() + m_signals.size());
#else
  sigset_t sigmask;
  std::vector<struct pollfd> read_fds;
  read_fds.reserve(m_read_fds.size());
#endif

  // run until termination or until we run out of things to listen to
  while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
    // To avoid problems with callbacks changing the things we're supposed to
    // listen to, we
    // will store the *real* list of events separately.
    signals.clear();

#if HAVE_SYS_EVENT_H
    events.resize(m_read_fds.size() + m_signals.size());
    int i = 0;
    for (auto &fd: m_read_fds) {
      EV_SET(&events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
    }

    for (const auto &sig : m_signals) {
      signals.push_back(sig.first);
      EV_SET(&events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
    }

    struct kevent event_list[4];
    int num_events =
        kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);

    if (num_events < 0)
      return Error("kevent() failed with error %d\n", num_events);

#else
    read_fds.clear();

#if !SIGNAL_POLLING_UNSUPPORTED
    if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask))
      return Error("pthread_sigmask failed with error %d\n", ret);

    for (const auto &sig : m_signals) {
      signals.push_back(sig.first);
      sigdelset(&sigmask, sig.first);
    }
#endif

    for (const auto &fd : m_read_fds) {
      struct pollfd pfd;
      pfd.fd = fd.first;
      pfd.events = POLLIN;
      pfd.revents = 0;
      read_fds.push_back(pfd);
    }

    if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
        errno != EINTR)
      return Error(errno, eErrorTypePOSIX);
#endif

    for (int sig : signals) {
      if (g_signal_flags[sig] == 0)
        continue; // No signal
      g_signal_flags[sig] = 0;

      auto it = m_signals.find(sig);
      if (it == m_signals.end())
        continue; // Signal must have gotten unregistered in the meantime

      it->second.callback(*this); // Do the work

      if (m_terminate_request)
        return Error();
    }

#if HAVE_SYS_EVENT_H
    for (int i = 0; i < num_events; ++i) {
      auto it = m_read_fds.find(event_list[i].ident);
#else
    for (auto fd : read_fds) {
      if ((fd.revents & POLLIN) == 0)
        continue;

      auto it = m_read_fds.find(fd.fd);
#endif
      if (it == m_read_fds.end())
        continue; // File descriptor must have gotten unregistered in the
                  // meantime
      it->second(*this); // Do the work

      if (m_terminate_request)
        return Error();
    }
  }
  return Error();
}
<commit_msg>One more attempt and Windows<commit_after>//===-- MainLoop.cpp --------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Config/config.h"

#include "lldb/Host/MainLoop.h"
#include "lldb/Utility/Error.h"
#include <algorithm>
#include <cassert>
#include <cerrno>
#include <csignal>
#include <vector>
#include <time.h>

#if HAVE_SYS_EVENT_H
#include <sys/event.h>
#elif defined(LLVM_ON_WIN32)
#include <winsock2.h>
#else
#include <poll.h>
#endif

#ifdef LLVM_ON_WIN32
#define POLL WSAPoll
#else
#define POLL poll
#endif

#if SIGNAL_POLLING_UNSUPPORTED
#ifdef LLVM_ON_WIN32
typedef int sigset_t;
typedef int siginfo_t;
#endif

int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts,
          const sigset_t *) {
  int timeout =
      (timeout_ts == nullptr)
          ? -1
          : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
  return POLL(fds, nfds, timeout);
}

#endif

using namespace lldb;
using namespace lldb_private;

static sig_atomic_t g_signal_flags[NSIG];

static void SignalHandler(int signo, siginfo_t *info, void *) {
  assert(signo < NSIG);
  g_signal_flags[signo] = 1;
}

MainLoop::~MainLoop() {
  assert(m_read_fds.size() == 0);
  assert(m_signals.size() == 0);
}

MainLoop::ReadHandleUP
MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
                                  const Callback &callback, Error &error) {
#ifdef LLVM_ON_WIN32
  if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) {
    error.SetErrorString("MainLoop: non-socket types unsupported on Windows");
    return nullptr;
  }
#endif
  if (!object_sp || !object_sp->IsValid()) {
    error.SetErrorString("IO object is not valid.");
    return nullptr;
  }

  const bool inserted =
      m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
  if (!inserted) {
    error.SetErrorStringWithFormat("File descriptor %d already monitored.",
                                   object_sp->GetWaitableHandle());
    return nullptr;
  }

  return CreateReadHandle(object_sp);
}

// We shall block the signal, then install the signal handler. The signal will
// be unblocked in
// the Run() function to check for signal delivery.
MainLoop::SignalHandleUP
MainLoop::RegisterSignal(int signo, const Callback &callback,
                              Error &error) {
#ifdef SIGNAL_POLLING_UNSUPPORTED
  error.SetErrorString("Signal polling is not supported on this platform.");
  return nullptr;
#else
  if (m_signals.find(signo) != m_signals.end()) {
    error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
    return nullptr;
  }

  SignalInfo info;
  info.callback = callback;
  struct sigaction new_action;
  new_action.sa_sigaction = &SignalHandler;
  new_action.sa_flags = SA_SIGINFO;
  sigemptyset(&new_action.sa_mask);
  sigaddset(&new_action.sa_mask, signo);

  sigset_t old_set;
  if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) {
    error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n",
                                   ret);
    return nullptr;
  }

  info.was_blocked = sigismember(&old_set, signo);
  if (sigaction(signo, &new_action, &info.old_action) == -1) {
    error.SetErrorToErrno();
    if (!info.was_blocked)
      pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr);
    return nullptr;
  }

  m_signals.insert({signo, info});
  g_signal_flags[signo] = 0;

  return SignalHandleUP(new SignalHandle(*this, signo));
#endif
}

void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
  bool erased = m_read_fds.erase(handle);
  UNUSED_IF_ASSERT_DISABLED(erased);
  assert(erased);
}

void MainLoop::UnregisterSignal(int signo) {
#if SIGNAL_POLLING_UNSUPPORTED
  Error("Signal polling is not supported on this platform.");
#else
  // We undo the actions of RegisterSignal on a best-effort basis.
  auto it = m_signals.find(signo);
  assert(it != m_signals.end());

  sigaction(signo, &it->second.old_action, nullptr);

  sigset_t set;
  sigemptyset(&set);
  sigaddset(&set, signo);
  pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set,
                  nullptr);

  m_signals.erase(it);
#endif
}

Error MainLoop::Run() {
  std::vector<int> signals;
  m_terminate_request = false;
  signals.reserve(m_signals.size());

#if HAVE_SYS_EVENT_H
  int queue_id = kqueue();
  if (queue_id < 0)
    Error("kqueue failed with error %d\n", queue_id);

  std::vector<struct kevent> events;
  events.reserve(m_read_fds.size() + m_signals.size());
#else
  sigset_t sigmask;
  std::vector<struct pollfd> read_fds;
  read_fds.reserve(m_read_fds.size());
#endif

  // run until termination or until we run out of things to listen to
  while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
    // To avoid problems with callbacks changing the things we're supposed to
    // listen to, we
    // will store the *real* list of events separately.
    signals.clear();

#if HAVE_SYS_EVENT_H
    events.resize(m_read_fds.size() + m_signals.size());
    int i = 0;
    for (auto &fd: m_read_fds) {
      EV_SET(&events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
    }

    for (const auto &sig : m_signals) {
      signals.push_back(sig.first);
      EV_SET(&events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
    }

    struct kevent event_list[4];
    int num_events =
        kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);

    if (num_events < 0)
      return Error("kevent() failed with error %d\n", num_events);

#else
    read_fds.clear();

#if !SIGNAL_POLLING_UNSUPPORTED
    if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask))
      return Error("pthread_sigmask failed with error %d\n", ret);

    for (const auto &sig : m_signals) {
      signals.push_back(sig.first);
      sigdelset(&sigmask, sig.first);
    }
#endif

    for (const auto &fd : m_read_fds) {
      struct pollfd pfd;
      pfd.fd = fd.first;
      pfd.events = POLLIN;
      pfd.revents = 0;
      read_fds.push_back(pfd);
    }

    if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
        errno != EINTR)
      return Error(errno, eErrorTypePOSIX);
#endif

    for (int sig : signals) {
      if (g_signal_flags[sig] == 0)
        continue; // No signal
      g_signal_flags[sig] = 0;

      auto it = m_signals.find(sig);
      if (it == m_signals.end())
        continue; // Signal must have gotten unregistered in the meantime

      it->second.callback(*this); // Do the work

      if (m_terminate_request)
        return Error();
    }

#if HAVE_SYS_EVENT_H
    for (int i = 0; i < num_events; ++i) {
      auto it = m_read_fds.find(event_list[i].ident);
#else
    for (auto fd : read_fds) {
      if ((fd.revents & POLLIN) == 0)
        continue;

      auto it = m_read_fds.find(fd.fd);
#endif
      if (it == m_read_fds.end())
        continue; // File descriptor must have gotten unregistered in the
                  // meantime
      it->second(*this); // Do the work

      if (m_terminate_request)
        return Error();
    }
  }
  return Error();
}
<|endoftext|>


<commit_before>
//#include <Python.h> // includes stdio.h, string.h, errno.h, stdlib.h
//#include <numpy/arrayobject.h>
#include "stdlib.h"
#include "math.h"
#include "voro_iface.h"
#include "voro++.hh"
#include <vector>

using namespace voro;

static int processAtomCell(voronoicell_neighbor&, int, double*, vorores_t*);

/*******************************************************************************
 * Main interface function to be called from C
 *******************************************************************************/
extern "C" int computeVoronoiVoroPlusPlusWrapper(int NAtoms, double *pos, int *PBC,
        double *bound_lo, double *bound_hi, int useRadii, double *radii, vorores_t *voroResult)
{
    int i;

    /* number of cells for spatial decomposition */
    double n[3];
    for (i = 0; i < 3; i++) n[i] = bound_hi[i] - bound_lo[i];
    double V = n[0] * n[1] * n[2];
    for (i = 0; i < 3; i++)
    {
        n[i] = round(n[i] * pow(double(NAtoms) / (V * 8.0), 0.333333));
        n[i] = n[i] == 0 ? 1 : n[i];
        printf("DEBUG: n[%d] = %lf\n", i, n[i]);
    }

    // voro cell with neighbour information
    voronoicell_neighbor c;

    // use radii or not
    if (useRadii)
    {
        /* initialise voro++ container, preallocates 8 atoms per cell */
        container_poly con(bound_lo[0], bound_hi[0],
                           bound_lo[1], bound_hi[1],
                           bound_lo[2], bound_hi[2],
                           int(n[0]),int(n[1]),int(n[2]),
                           bool(PBC[0]), bool(PBC[1]), bool(PBC[2]), 8);

        // pass coordinates for local and ghost atoms to voro++
        for (i = 0; i < NAtoms; i++)
            con.put(i, pos[3*i], pos[3*i+1], pos[3*i+2], radii[i]);

        // invoke voro++ and fetch results for owned atoms in group
        int count = 0;
        c_loop_all cl(con);
        if (cl.start()) do if (con.compute_cell(c,cl))
        {
            i = cl.pid();
            processAtomCell(c, i, pos, voroResult);
            count++;
        } while (cl.inc());

        printf("DEBUG: COUNT = %d (%d atoms)\n", count, NAtoms);
    }
    else
    {
        /* initialise voro++ container, preallocates 8 atoms per cell */
        container con(bound_lo[0], bound_hi[0],
                      bound_lo[1], bound_hi[1],
                      bound_lo[2], bound_hi[2],
                      int(n[0]),int(n[1]),int(n[2]),
                      bool(PBC[0]), bool(PBC[1]), bool(PBC[2]), 8);

        // pass coordinates for local and ghost atoms to voro++
        for (i = 0; i < NAtoms; i++)
            con.put(i, pos[3*i], pos[3*i+1], pos[3*i+2]);

        // invoke voro++ and fetch results for owned atoms in group
        int count = 0;
        int errcnt = 0;
        c_loop_all cl(con);
        if (cl.start()) do if (con.compute_cell(c,cl))
        {
            int retval;

            i = cl.pid();
            retval = processAtomCell(c, i, pos, voroResult);

            if (retval)
            {
                errcnt++;
            }

            count++;
        } while (cl.inc());
        printf("DEBUG: COUNT = %d (%d atoms)\n", count, NAtoms);

        /* return error */
        if (errcnt) return -1;
    }

    return 0;
}

/*******************************************************************************
 * Process cell; compute volume, num neighbours, facets etc.
 *******************************************************************************/
static int processAtomCell(voronoicell_neighbor &c, int i, double *pos, vorores_t *voroResult)
{
    /* initialise result */
    voroResult[i].numFaces = 0;
    voroResult[i].numNeighbours = 0;
    voroResult[i].numVertices = 0;

    /* volume */
    voroResult[i].volume = c.volume();

    /* number of neighbours (should add threshold) */
    std::vector<int> neighbours;
    c.neighbors(neighbours);
    int nnebs = neighbours.size(); // this will change if add threshold...
    voroResult[i].neighbours = (int*) malloc(nnebs * sizeof(int));
    if (voroResult[i].neighbours == NULL) return -1;
    for (int j = 0; j < nnebs; j++)
        voroResult[i].neighbours[j] = neighbours[j];
    voroResult[i].numNeighbours = nnebs;

    /* vertices */
    std::vector<double> vertices;
    c.vertices(pos[3*i], pos[3*i+1], pos[3*i+2], vertices);
    int nvertices = c.p;
    voroResult[i].vertices = (double*) malloc(3 * nvertices * sizeof(double));
    if (voroResult[i].vertices == NULL) return -1;
    for (int j = 0; j < nvertices; j++)
    {
        int j3 = 3 * j;
        voroResult[i].vertices[j3] = vertices[j3];
        voroResult[i].vertices[j3+1] = vertices[j3+1];
        voroResult[i].vertices[j3+2] = vertices[j3+2];
    }
    voroResult[i].numVertices = nvertices;

    /* faces */
    std::vector<int> faceVertices;
    c.face_vertices(faceVertices);
    int nfaces = c.number_of_faces();

    voroResult[i].numFaceVertices = (int*) calloc(nfaces, sizeof(int));
    if (voroResult[i].numFaceVertices == NULL) return -1;

    voroResult[i].faceVertices = (int**) malloc(nfaces * sizeof(int*));
    if (voroResult[i].faceVertices == NULL) return -1;

    voroResult[i].numFaces = nfaces;

    int count = 0;
    for (int j = 0; j < nfaces; j++)
    {
        int nfaceverts = faceVertices[count++];

        /* allocate space for this faces vertices */
        voroResult[i].faceVertices[j] = (int*) malloc(nfaceverts * sizeof(int));
        if (voroResult[i].faceVertices[j] == NULL) return -1;
        voroResult[i].numFaceVertices[j] = nfaceverts;

        for (int k = 0; k < nfaceverts; k++)
            voroResult[i].faceVertices[j][k] = faceVertices[count++];
    }

    /* original position */
    voroResult[i].originalPos[0] = pos[3*i];
    voroResult[i].originalPos[1] = pos[3*i+1];
    voroResult[i].originalPos[2] = pos[3*i+2];

    return 0;
}
<commit_msg>Add header<commit_after>
/*******************************************************************************
 ** Copyright Chris Scott 2014
 ** Interface to Voro++
 *******************************************************************************/

#include "stdlib.h"
#include "math.h"
#include "voro_iface.h"
#include "voro++.hh"
#include <vector>

using namespace voro;

static int processAtomCell(voronoicell_neighbor&, int, double*, vorores_t*);

/*******************************************************************************
 * Main interface function to be called from C
 *******************************************************************************/
extern "C" int computeVoronoiVoroPlusPlusWrapper(int NAtoms, double *pos, int *PBC,
        double *bound_lo, double *bound_hi, int useRadii, double *radii, vorores_t *voroResult)
{
    int i;

    /* number of cells for spatial decomposition */
    double n[3];
    for (i = 0; i < 3; i++) n[i] = bound_hi[i] - bound_lo[i];
    double V = n[0] * n[1] * n[2];
    for (i = 0; i < 3; i++)
    {
        n[i] = round(n[i] * pow(double(NAtoms) / (V * 8.0), 0.333333));
        n[i] = n[i] == 0 ? 1 : n[i];
        printf("DEBUG: n[%d] = %lf\n", i, n[i]);
    }

    // voro cell with neighbour information
    voronoicell_neighbor c;

    // use radii or not
    if (useRadii)
    {
        /* initialise voro++ container, preallocates 8 atoms per cell */
        container_poly con(bound_lo[0], bound_hi[0],
                           bound_lo[1], bound_hi[1],
                           bound_lo[2], bound_hi[2],
                           int(n[0]),int(n[1]),int(n[2]),
                           bool(PBC[0]), bool(PBC[1]), bool(PBC[2]), 8);

        // pass coordinates for local and ghost atoms to voro++
        for (i = 0; i < NAtoms; i++)
            con.put(i, pos[3*i], pos[3*i+1], pos[3*i+2], radii[i]);

        // invoke voro++ and fetch results for owned atoms in group
        int count = 0;
        c_loop_all cl(con);
        if (cl.start()) do if (con.compute_cell(c,cl))
        {
            i = cl.pid();
            processAtomCell(c, i, pos, voroResult);
            count++;
        } while (cl.inc());

        printf("DEBUG: COUNT = %d (%d atoms)\n", count, NAtoms);
    }
    else
    {
        /* initialise voro++ container, preallocates 8 atoms per cell */
        container con(bound_lo[0], bound_hi[0],
                      bound_lo[1], bound_hi[1],
                      bound_lo[2], bound_hi[2],
                      int(n[0]),int(n[1]),int(n[2]),
                      bool(PBC[0]), bool(PBC[1]), bool(PBC[2]), 8);

        // pass coordinates for local and ghost atoms to voro++
        for (i = 0; i < NAtoms; i++)
            con.put(i, pos[3*i], pos[3*i+1], pos[3*i+2]);

        // invoke voro++ and fetch results for owned atoms in group
        int count = 0;
        int errcnt = 0;
        c_loop_all cl(con);
        if (cl.start()) do if (con.compute_cell(c,cl))
        {
            int retval;

            i = cl.pid();
            retval = processAtomCell(c, i, pos, voroResult);

            if (retval)
            {
                errcnt++;
            }

            count++;
        } while (cl.inc());
        printf("DEBUG: COUNT = %d (%d atoms)\n", count, NAtoms);

        /* return error */
        if (errcnt) return -1;
    }

    return 0;
}

/*******************************************************************************
 * Process cell; compute volume, num neighbours, facets etc.
 *******************************************************************************/
static int processAtomCell(voronoicell_neighbor &c, int i, double *pos, vorores_t *voroResult)
{
    /* initialise result */
    voroResult[i].numFaces = 0;
    voroResult[i].numNeighbours = 0;
    voroResult[i].numVertices = 0;

    /* volume */
    voroResult[i].volume = c.volume();

    /* number of neighbours (should add threshold) */
    std::vector<int> neighbours;
    c.neighbors(neighbours);
    int nnebs = neighbours.size(); // this will change if add threshold...
    voroResult[i].neighbours = (int*) malloc(nnebs * sizeof(int));
    if (voroResult[i].neighbours == NULL) return -1;
    for (int j = 0; j < nnebs; j++)
        voroResult[i].neighbours[j] = neighbours[j];
    voroResult[i].numNeighbours = nnebs;

    /* vertices */
    std::vector<double> vertices;
    c.vertices(pos[3*i], pos[3*i+1], pos[3*i+2], vertices);
    int nvertices = c.p;
    voroResult[i].vertices = (double*) malloc(3 * nvertices * sizeof(double));
    if (voroResult[i].vertices == NULL) return -1;
    for (int j = 0; j < nvertices; j++)
    {
        int j3 = 3 * j;
        voroResult[i].vertices[j3] = vertices[j3];
        voroResult[i].vertices[j3+1] = vertices[j3+1];
        voroResult[i].vertices[j3+2] = vertices[j3+2];
    }
    voroResult[i].numVertices = nvertices;

    /* faces */
    std::vector<int> faceVertices;
    c.face_vertices(faceVertices);
    int nfaces = c.number_of_faces();

    voroResult[i].numFaceVertices = (int*) calloc(nfaces, sizeof(int));
    if (voroResult[i].numFaceVertices == NULL) return -1;

    voroResult[i].faceVertices = (int**) malloc(nfaces * sizeof(int*));
    if (voroResult[i].faceVertices == NULL) return -1;

    voroResult[i].numFaces = nfaces;

    int count = 0;
    for (int j = 0; j < nfaces; j++)
    {
        int nfaceverts = faceVertices[count++];

        /* allocate space for this faces vertices */
        voroResult[i].faceVertices[j] = (int*) malloc(nfaceverts * sizeof(int));
        if (voroResult[i].faceVertices[j] == NULL) return -1;
        voroResult[i].numFaceVertices[j] = nfaceverts;

        for (int k = 0; k < nfaceverts; k++)
            voroResult[i].faceVertices[j][k] = faceVertices[count++];
    }

    /* original position */
    voroResult[i].originalPos[0] = pos[3*i];
    voroResult[i].originalPos[1] = pos[3*i+1];
    voroResult[i].originalPos[2] = pos[3*i+2];

    return 0;
}
<|endoftext|>


<commit_before>//===-- MainLoop.cpp --------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Config/config.h"

#include "lldb/Host/MainLoop.h"
#include "lldb/Utility/Error.h"
#include <algorithm>
#include <cassert>
#include <cerrno>
#include <csignal>
#include <vector>

#if HAVE_SYS_EVENT_H
#include <sys/event.h>
#elif defined(LLVM_ON_WIN32)
#include <winsock2.h>
#else
#include <poll.h>
#endif

#ifdef LLVM_ON_WIN32
#define POLL WSAPoll
#else
#define POLL poll
#endif

#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H

int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts,
          const sigset_t *) {
  int timeout =
      (timeout_ts == nullptr)
          ? -1
          : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
  return POLL(fds, nfds, timeout);
}

#endif

using namespace lldb;
using namespace lldb_private;

static sig_atomic_t g_signal_flags[NSIG];

static void SignalHandler(int signo, siginfo_t *info, void *) {
  assert(signo < NSIG);
  g_signal_flags[signo] = 1;
}

MainLoop::~MainLoop() {
  assert(m_read_fds.size() == 0);
  assert(m_signals.size() == 0);
}

MainLoop::ReadHandleUP
MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
                                  const Callback &callback, Error &error) {
#ifdef LLVM_ON_WIN32
  if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) {
    error.SetErrorString("MainLoop: non-socket types unsupported on Windows");
    return nullptr;
  }
#endif
  if (!object_sp || !object_sp->IsValid()) {
    error.SetErrorString("IO object is not valid.");
    return nullptr;
  }

  const bool inserted =
      m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
  if (!inserted) {
    error.SetErrorStringWithFormat("File descriptor %d already monitored.",
                                   object_sp->GetWaitableHandle());
    return nullptr;
  }

  return CreateReadHandle(object_sp);
}

// We shall block the signal, then install the signal handler. The signal will
// be unblocked in
// the Run() function to check for signal delivery.
MainLoop::SignalHandleUP
MainLoop::RegisterSignal(int signo, const Callback &callback,
                              Error &error) {
#ifdef SIGNAL_POLLING_UNSUPPORTED
  error.SetErrorString("Signal polling is not supported on this platform.");
  return nullptr;
#else
  if (m_signals.find(signo) != m_signals.end()) {
    error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
    return nullptr;
  }

  SignalInfo info;
  info.callback = callback;
  struct sigaction new_action;
  new_action.sa_sigaction = &SignalHandler;
  new_action.sa_flags = SA_SIGINFO;
  sigemptyset(&new_action.sa_mask);
  sigaddset(&new_action.sa_mask, signo);

  sigset_t old_set;
  if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) {
    error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n",
                                   ret);
    return nullptr;
  }

  info.was_blocked = sigismember(&old_set, signo);
  if (sigaction(signo, &new_action, &info.old_action) == -1) {
    error.SetErrorToErrno();
    if (!info.was_blocked)
      pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr);
    return nullptr;
  }

  m_signals.insert({signo, info});
  g_signal_flags[signo] = 0;

  return SignalHandleUP(new SignalHandle(*this, signo));
#endif
}

void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
  bool erased = m_read_fds.erase(handle);
  UNUSED_IF_ASSERT_DISABLED(erased);
  assert(erased);
}

void MainLoop::UnregisterSignal(int signo) {
  // We undo the actions of RegisterSignal on a best-effort basis.
  auto it = m_signals.find(signo);
  assert(it != m_signals.end());

  sigaction(signo, &it->second.old_action, nullptr);

  sigset_t set;
  sigemptyset(&set);
  sigaddset(&set, signo);
  pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set,
                  nullptr);

  m_signals.erase(it);
}

Error MainLoop::Run() {
  std::vector<int> signals;
  sigset_t sigmask;
  m_terminate_request = false;
  signals.reserve(m_signals.size());

#if HAVE_SYS_EVENT_H
  int queue_id = kqueue();
  if (queue_id < 0)
    Error("kqueue failed with error %d\n", queue_id);

  std::vector<struct kevent> events;
  events.reserve(m_read_fds.size() + m_signals.size());
#else
  std::vector<struct pollfd> read_fds;
  read_fds.reserve(m_read_fds.size());
#endif

  // run until termination or until we run out of things to listen to
  while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
    // To avoid problems with callbacks changing the things we're supposed to
    // listen to, we
    // will store the *real* list of events separately.
    signals.clear();

#if HAVE_SYS_EVENT_H
    events.resize(m_read_fds.size() + m_signals.size());
    int i = 0;
    for (auto &fd: m_read_fds) {
      EV_SET(&events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
    }

    for (const auto &sig : m_signals) {
      signals.push_back(sig.first);
      EV_SET(&events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
    }

    struct kevent event_list[4];
    int num_events =
        kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);

    if (num_events < 0)
      return Error("kevent() failed with error %d\n", num_events);

#else
    read_fds.clear();
    if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask))
      return Error("pthread_sigmask failed with error %d\n", ret);

    for (const auto &fd : m_read_fds) {
      struct pollfd pfd;
      pfd.fd = fd.first;
      pfd.events = POLLIN;
      pfd.revents = 0;
      read_fds.push_back(pfd);
    }

    for (const auto &sig : m_signals) {
      signals.push_back(sig.first);
      sigdelset(&sigmask, sig.first);
    }

    if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
        errno != EINTR)
      return Error(errno, eErrorTypePOSIX);
#endif

    for (int sig : signals) {
      if (g_signal_flags[sig] == 0)
        continue; // No signal
      g_signal_flags[sig] = 0;

      auto it = m_signals.find(sig);
      if (it == m_signals.end())
        continue; // Signal must have gotten unregistered in the meantime

      it->second.callback(*this); // Do the work

      if (m_terminate_request)
        return Error();
    }

#if HAVE_SYS_EVENT_H
    for (int i = 0; i < num_events; ++i) {
      auto it = m_read_fds.find(event_list[i].ident);
#else
    for (auto fd : read_fds) {
      if ((fd.revents & POLLIN) == 0)
        continue;

      auto it = m_read_fds.find(fd.fd);
#endif
      if (it == m_read_fds.end())
        continue; // File descriptor must have gotten unregistered in the
                  // meantime
      it->second(*this); // Do the work

      if (m_terminate_request)
        return Error();
    }
  }
  return Error();
}
<commit_msg>Fix Windows bot failure<commit_after>//===-- MainLoop.cpp --------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Config/config.h"

#include "lldb/Host/MainLoop.h"
#include "lldb/Utility/Error.h"
#include <algorithm>
#include <cassert>
#include <cerrno>
#include <csignal>
#include <vector>

#if HAVE_SYS_EVENT_H
#include <sys/event.h>
#elif defined(LLVM_ON_WIN32)
#include <winsock2.h>
#else
#include <poll.h>
#endif

#ifdef LLVM_ON_WIN32
#define POLL WSAPoll
#else
#define POLL poll
#endif

#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H

#ifdef LLVM_ON_WIN32
struct timespec {
  time_t       tv_sec;
  suseconds_t  tv_nsec;
};
#endif

int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts,
          const sigset_t *) {
  int timeout =
      (timeout_ts == nullptr)
          ? -1
          : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
  return POLL(fds, nfds, timeout);
}

#endif

using namespace lldb;
using namespace lldb_private;

static sig_atomic_t g_signal_flags[NSIG];

static void SignalHandler(int signo, siginfo_t *info, void *) {
  assert(signo < NSIG);
  g_signal_flags[signo] = 1;
}

MainLoop::~MainLoop() {
  assert(m_read_fds.size() == 0);
  assert(m_signals.size() == 0);
}

MainLoop::ReadHandleUP
MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
                                  const Callback &callback, Error &error) {
#ifdef LLVM_ON_WIN32
  if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) {
    error.SetErrorString("MainLoop: non-socket types unsupported on Windows");
    return nullptr;
  }
#endif
  if (!object_sp || !object_sp->IsValid()) {
    error.SetErrorString("IO object is not valid.");
    return nullptr;
  }

  const bool inserted =
      m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
  if (!inserted) {
    error.SetErrorStringWithFormat("File descriptor %d already monitored.",
                                   object_sp->GetWaitableHandle());
    return nullptr;
  }

  return CreateReadHandle(object_sp);
}

// We shall block the signal, then install the signal handler. The signal will
// be unblocked in
// the Run() function to check for signal delivery.
MainLoop::SignalHandleUP
MainLoop::RegisterSignal(int signo, const Callback &callback,
                              Error &error) {
#ifdef SIGNAL_POLLING_UNSUPPORTED
  error.SetErrorString("Signal polling is not supported on this platform.");
  return nullptr;
#else
  if (m_signals.find(signo) != m_signals.end()) {
    error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
    return nullptr;
  }

  SignalInfo info;
  info.callback = callback;
  struct sigaction new_action;
  new_action.sa_sigaction = &SignalHandler;
  new_action.sa_flags = SA_SIGINFO;
  sigemptyset(&new_action.sa_mask);
  sigaddset(&new_action.sa_mask, signo);

  sigset_t old_set;
  if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) {
    error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n",
                                   ret);
    return nullptr;
  }

  info.was_blocked = sigismember(&old_set, signo);
  if (sigaction(signo, &new_action, &info.old_action) == -1) {
    error.SetErrorToErrno();
    if (!info.was_blocked)
      pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr);
    return nullptr;
  }

  m_signals.insert({signo, info});
  g_signal_flags[signo] = 0;

  return SignalHandleUP(new SignalHandle(*this, signo));
#endif
}

void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
  bool erased = m_read_fds.erase(handle);
  UNUSED_IF_ASSERT_DISABLED(erased);
  assert(erased);
}

void MainLoop::UnregisterSignal(int signo) {
  // We undo the actions of RegisterSignal on a best-effort basis.
  auto it = m_signals.find(signo);
  assert(it != m_signals.end());

  sigaction(signo, &it->second.old_action, nullptr);

  sigset_t set;
  sigemptyset(&set);
  sigaddset(&set, signo);
  pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set,
                  nullptr);

  m_signals.erase(it);
}

Error MainLoop::Run() {
  std::vector<int> signals;
  sigset_t sigmask;
  m_terminate_request = false;
  signals.reserve(m_signals.size());

#if HAVE_SYS_EVENT_H
  int queue_id = kqueue();
  if (queue_id < 0)
    Error("kqueue failed with error %d\n", queue_id);

  std::vector<struct kevent> events;
  events.reserve(m_read_fds.size() + m_signals.size());
#else
  std::vector<struct pollfd> read_fds;
  read_fds.reserve(m_read_fds.size());
#endif

  // run until termination or until we run out of things to listen to
  while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
    // To avoid problems with callbacks changing the things we're supposed to
    // listen to, we
    // will store the *real* list of events separately.
    signals.clear();

#if HAVE_SYS_EVENT_H
    events.resize(m_read_fds.size() + m_signals.size());
    int i = 0;
    for (auto &fd: m_read_fds) {
      EV_SET(&events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
    }

    for (const auto &sig : m_signals) {
      signals.push_back(sig.first);
      EV_SET(&events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
    }

    struct kevent event_list[4];
    int num_events =
        kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);

    if (num_events < 0)
      return Error("kevent() failed with error %d\n", num_events);

#else
    read_fds.clear();
    if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask))
      return Error("pthread_sigmask failed with error %d\n", ret);

    for (const auto &fd : m_read_fds) {
      struct pollfd pfd;
      pfd.fd = fd.first;
      pfd.events = POLLIN;
      pfd.revents = 0;
      read_fds.push_back(pfd);
    }

    for (const auto &sig : m_signals) {
      signals.push_back(sig.first);
      sigdelset(&sigmask, sig.first);
    }

    if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
        errno != EINTR)
      return Error(errno, eErrorTypePOSIX);
#endif

    for (int sig : signals) {
      if (g_signal_flags[sig] == 0)
        continue; // No signal
      g_signal_flags[sig] = 0;

      auto it = m_signals.find(sig);
      if (it == m_signals.end())
        continue; // Signal must have gotten unregistered in the meantime

      it->second.callback(*this); // Do the work

      if (m_terminate_request)
        return Error();
    }

#if HAVE_SYS_EVENT_H
    for (int i = 0; i < num_events; ++i) {
      auto it = m_read_fds.find(event_list[i].ident);
#else
    for (auto fd : read_fds) {
      if ((fd.revents & POLLIN) == 0)
        continue;

      auto it = m_read_fds.find(fd.fd);
#endif
      if (it == m_read_fds.end())
        continue; // File descriptor must have gotten unregistered in the
                  // meantime
      it->second(*this); // Do the work

      if (m_terminate_request)
        return Error();
    }
  }
  return Error();
}
<|endoftext|>


<commit_before>#include "Zenderer/Graphics/Scene.hpp"

using namespace zen;
using namespace gfx;

using util::CLog;
using util::LogMode;
using gfxcore::CRenderer;
using gfxcore::BlendFunc;

CScene::CScene(const uint16_t w, const uint16_t h, asset::CAssetManager& Mgr) :
    CSubsystem("Scene"), m_Assets(Mgr),
    m_Log(util::CLog::GetEngineLog()), m_FBO1(w, h), m_FBO2(w, h),
    m_lighting(false), m_ppfx(false), m_through(false)
{
}

CScene::~CScene()
{
    this->Destroy();
}

bool CScene::Init()
{
    return  m_Assets.IsInit()   && m_Geometry.Init() &&
            m_FBO1.Init()       && m_FBO2.Init();
}

/// @bug A crash occurs deleting entities.
bool CScene::Destroy()
{
    return this->Clear()    && m_FBO1.Destroy() &&
           m_FBO2.Destroy() && m_Geometry.Destroy();
}

obj::CEntity& CScene::AddEntity()
{
    obj::CEntity* pNew = new obj::CEntity(m_Assets);
    m_allEntities.push_back(pNew);
    return *m_allEntities.back();
}

CLight& CScene::AddLight(const LightType& Type)
{
    CLight* pNew = new CLight(m_Assets, Type, m_FBO1.GetHeight());
    pNew->Init();
    m_allLights.push_back(pNew);
    return *m_allLights.back();
}

CEffect& CScene::AddEffect(const EffectType& Type)
{
    CEffect* pNew = new CEffect(Type, m_Assets);
    if(pNew->Init())
    {
        pNew->Enable();
        pNew->SetParameter("mv", math::matrix4x4_t::GetIdentityMatrix());
        pNew->SetParameter("proj", CRenderer::GetProjectionMatrix());
        pNew->Disable();
    }

    m_allPPFX.push_back(pNew);
    return *m_allPPFX.back();
}

obj::CEntity& CScene::InsertEntity(const uint32_t index)
{
    obj::CEntity* pNew = new obj::CEntity(m_Assets);
    auto i = m_allEntities.begin();
    for(size_t j = 0, s = m_allEntities.size();
        j < s && j != index; ++j, ++i);
        // No -op

    m_allEntities.insert(i, pNew);
    return *pNew;
}

bool CScene::RemoveEntity(const obj::CEntity& Obj)
{
    auto i = m_allEntities.begin(),
         j = m_allEntities.end();

    for( ; i != j; ++i)
    {
        if(*i == &Obj)
        {
            delete *i;
            m_allEntities.erase(i);
            return true;
        }
    }

    return false;
}

bool CScene::RemoveEntity(const uint32_t index)
{
    if(!this->IsValidEntityIndex(index)) return false;

    auto i = m_allEntities.begin();
    for(size_t j = 0; j <= index; ++j, ++i);
        // No-op

    delete *i;
    m_allEntities.erase(i);
    return true;
}

bool CScene::Clear()
{
    for(auto i : m_allEntities) delete i;
    for(auto i : m_allLights) delete i;
    for(auto i : m_allPPFX) delete i;

    m_allEntities.clear();
    m_allLights.clear();
    m_allPPFX.clear();

    return m_Geometry.Clear();
}

bool CScene::Render()
{
    // Called every frame because there is no more appropriate
    // time to call it. Things won't be offloaded multiple times.
    for(auto& i : m_allEntities)
    {
        // If any are offloaded, the rest probably are too.
        if(i->Offloaded()) break;
        i->Offload(m_Geometry, false);
    }

    m_Geometry.Offload();

    // Clear our frame buffers from the last drawing.
    // We will be rendering to FBO1 at first.
    color4f_t Clear = color4f_t(0.0, 0.0, 0.0);
    if(m_through) Clear.a = 0.0;
    m_FBO2.Bind(); m_FBO2.Clear(Clear);
    m_FBO1.Bind(); m_FBO1.Clear(Clear);

    // Set the standard blending state.
    bool blend = CRenderer::BlendOperation(BlendFunc::IS_ENABLED);
    CRenderer::BlendOperation(BlendFunc::STANDARD_BLEND);

    // All geometry is stored here.
    m_Geometry.Bind();

    // Prepare for primitive rendering.
    const CMaterial& M = CRenderer::GetDefaultMaterial();
    CEffect& E = const_cast<CMaterial&>(M).GetEffect();
    M.Enable();

    // Commence individual primitive rendering.
    for(auto& i : m_allEntities)
    {
        if(!i->m_enabled) continue;

        // Adjust for the camera.
        i->Move(i->GetPosition() + m_Camera);

        // Set the matrix for transformation.
        const math::matrix4x4_t& Tmp = i->GetTransformation();
        E.SetParameter("mv", Tmp);

        auto a = i->cbegin(), b = i->cend();
        for( ; a != b; ++a)
        {
            (*a)->GetMaterial().Enable();
            (*a)->Draw(true);
        }

        // Move back to original position.
        i->Move(i->GetPosition() - m_Camera);
    }

    M.Disable();

    // Shortcut reference.
    gfxcore::CVertexArray& FS = CRenderer::GetFullscreenVBO();

    // Primitive rendering is complete.
    // Now, render lights with additive blending.
    GLuint final_texture = m_FBO1.GetTexture();

    if(m_lighting)
    {
        // We want to render to the entire scene.

        // Lighting renders ON the geometry, so we
        // bind the FBO1 texture to render onto. The
        // final result ends up on the FBO2 texture.
        m_FBO2.Bind();
        CRenderer::EnableTexture(final_texture);
        CRenderer::BlendOperation(BlendFunc::ADDITIVE_BLEND);

        for(auto& i : m_allLights)
        {
            i->Enable();

            // Move with scene
            i->Adjust(m_Camera.x, m_Camera.y);

            FS.Draw();

            // Restore state
            i->Adjust(-m_Camera.x, -m_Camera.y);
            i->Disable();
        }

        final_texture = m_FBO2.GetTexture();
        CRenderer::BlendOperation(BlendFunc::STANDARD_BLEND);
    }

    // Ping-pong post-processing effects.
    // This means one is drawn to FBO1, then FBO1's result
    // is used to draw on FBO2, etc.
    if(m_ppfx)
    {
        // If there was lighting, the first texture is
        // the second FBO.
        CRenderTarget& One = m_lighting ? m_FBO2 : m_FBO1;
        CRenderTarget& Two = m_lighting ? m_FBO1 : m_FBO2;

        auto i = m_allPPFX.begin(),
             j = m_allPPFX.end();

        for(size_t c = 0; i != j; ++i, ++c)
        {
            auto& FX = *i;
            bool even = ((c & 0x1) == 0);
            if(even)    Two.Bind();
            else        One.Bind();

            FX->Enable();
            CRenderer::EnableTexture(final_texture);
            FS.Draw();
            FX->Disable();

            final_texture = even ? Two.GetTexture() : One.GetTexture();
        }
    }

    // Now we have the final scene data in `final_texture`

    // Doesn't matter which we disable.
    m_FBO1.Unbind();

    E.Enable();
    CRenderer::EnableTexture(final_texture);
    if(!m_through) CRenderer::BlendOperation(BlendFunc::DISABLE_BLEND);
    GL(glDisable(GL_DEPTH_TEST));

    // Make sure the right data is set.
    E.SetParameter("mv", math::matrix4x4_t::GetIdentityMatrix());
    E.SetParameter("proj", CRenderer::GetProjectionMatrix());

    FS.Draw();

    CRenderer::EnableTexture(0);
    CRenderer::ResetMaterialState();

    if(!blend && m_through) CRenderer::BlendOperation(BlendFunc::DISABLE_BLEND);

    return true;
}

int32_t CScene::GetEntityIndex(const obj::CEntity& D)
{
    int32_t index = -1;
    for(auto i : m_allEntities)
    {
        ++index;
        if(i == &D) return index;
    }

    return index;
}

bool CScene::IsValidEntityIndex(int32_t i)
{
    return (i > 0 && i < m_allEntities.size());
}
<commit_msg>Always check all offloads for scene.<commit_after>#include "Zenderer/Graphics/Scene.hpp"

using namespace zen;
using namespace gfx;

using util::CLog;
using util::LogMode;
using gfxcore::CRenderer;
using gfxcore::BlendFunc;

CScene::CScene(const uint16_t w, const uint16_t h, asset::CAssetManager& Mgr) :
    CSubsystem("Scene"), m_Assets(Mgr),
    m_Log(util::CLog::GetEngineLog()), m_FBO1(w, h), m_FBO2(w, h),
    m_lighting(false), m_ppfx(false), m_through(false)
{
}

CScene::~CScene()
{
    this->Destroy();
}

bool CScene::Init()
{
    return  m_Assets.IsInit()   && m_Geometry.Init() &&
            m_FBO1.Init()       && m_FBO2.Init();
}

/// @bug A crash occurs deleting entities.
bool CScene::Destroy()
{
    return this->Clear()    && m_FBO1.Destroy() &&
           m_FBO2.Destroy() && m_Geometry.Destroy();
}

obj::CEntity& CScene::AddEntity()
{
    obj::CEntity* pNew = new obj::CEntity(m_Assets);
    m_allEntities.push_back(pNew);
    return *m_allEntities.back();
}

CLight& CScene::AddLight(const LightType& Type)
{
    CLight* pNew = new CLight(m_Assets, Type, m_FBO1.GetHeight());
    pNew->Init();
    m_allLights.push_back(pNew);
    return *m_allLights.back();
}

CEffect& CScene::AddEffect(const EffectType& Type)
{
    CEffect* pNew = new CEffect(Type, m_Assets);
    if(pNew->Init())
    {
        pNew->Enable();
        pNew->SetParameter("mv", math::matrix4x4_t::GetIdentityMatrix());
        pNew->SetParameter("proj", CRenderer::GetProjectionMatrix());
        pNew->Disable();
    }

    m_allPPFX.push_back(pNew);
    return *m_allPPFX.back();
}

obj::CEntity& CScene::InsertEntity(const uint32_t index)
{
    obj::CEntity* pNew = new obj::CEntity(m_Assets);
    auto i = m_allEntities.begin();
    for(size_t j = 0, s = m_allEntities.size();
        j < s && j != index; ++j, ++i);
        // No -op

    m_allEntities.insert(i, pNew);
    return *pNew;
}

bool CScene::RemoveEntity(const obj::CEntity& Obj)
{
    auto i = m_allEntities.begin(),
         j = m_allEntities.end();

    for( ; i != j; ++i)
    {
        if(*i == &Obj)
        {
            delete *i;
            m_allEntities.erase(i);
            return true;
        }
    }

    return false;
}

bool CScene::RemoveEntity(const uint32_t index)
{
    if(!this->IsValidEntityIndex(index)) return false;

    auto i = m_allEntities.begin();
    for(size_t j = 0; j <= index; ++j, ++i);
        // No-op

    delete *i;
    m_allEntities.erase(i);
    return true;
}

bool CScene::Clear()
{
    for(auto i : m_allEntities) delete i;
    for(auto i : m_allLights) delete i;
    for(auto i : m_allPPFX) delete i;

    m_allEntities.clear();
    m_allLights.clear();
    m_allPPFX.clear();

    return m_Geometry.Clear();
}

bool CScene::Render()
{
    // Called every frame because there is no more appropriate
    // time to call it. Things won't be offloaded multiple times.
    for(auto& i : m_allEntities)
    {
        // If any are offloaded, the rest probably are too.
        if(i->Offloaded()) continue;
        i->Offload(m_Geometry, false);
    }

    m_Geometry.Offload();

    // Clear our frame buffers from the last drawing.
    // We will be rendering to FBO1 at first.
    color4f_t Clear = color4f_t(0.0, 0.0, 0.0);
    if(m_through) Clear.a = 0.0;
    m_FBO2.Bind(); m_FBO2.Clear(Clear);
    m_FBO1.Bind(); m_FBO1.Clear(Clear);

    // Set the standard blending state.
    bool blend = CRenderer::BlendOperation(BlendFunc::IS_ENABLED);
    CRenderer::BlendOperation(BlendFunc::STANDARD_BLEND);

    // All geometry is stored here.
    m_Geometry.Bind();

    // Prepare for primitive rendering.
    const CMaterial& M = CRenderer::GetDefaultMaterial();
    CEffect& E = const_cast<CMaterial&>(M).GetEffect();
    M.Enable();

    // Commence individual primitive rendering.
    for(auto& i : m_allEntities)
    {
        if(!i->m_enabled) continue;

        // Adjust for the camera.
        i->Move(i->GetPosition() + m_Camera);

        // Set the matrix for transformation.
        const math::matrix4x4_t& Tmp = i->GetTransformation();
        E.SetParameter("mv", Tmp);

        auto a = i->cbegin(), b = i->cend();
        for( ; a != b; ++a)
        {
            (*a)->GetMaterial().Enable();
            (*a)->Draw(true);
        }

        // Move back to original position.
        i->Move(i->GetPosition() - m_Camera);
    }

    M.Disable();

    // Shortcut reference.
    gfxcore::CVertexArray& FS = CRenderer::GetFullscreenVBO();

    // Primitive rendering is complete.
    // Now, render lights with additive blending.
    GLuint final_texture = m_FBO1.GetTexture();

    if(m_lighting)
    {
        // We want to render to the entire scene.

        // Lighting renders ON the geometry, so we
        // bind the FBO1 texture to render onto. The
        // final result ends up on the FBO2 texture.
        m_FBO2.Bind();
        CRenderer::EnableTexture(final_texture);
        CRenderer::BlendOperation(BlendFunc::ADDITIVE_BLEND);

        for(auto& i : m_allLights)
        {
            i->Enable();

            // Move with scene
            i->Adjust(m_Camera.x, m_Camera.y);

            FS.Draw();

            // Restore state
            i->Adjust(-m_Camera.x, -m_Camera.y);
            i->Disable();
        }

        final_texture = m_FBO2.GetTexture();
        CRenderer::BlendOperation(BlendFunc::STANDARD_BLEND);
    }

    // Ping-pong post-processing effects.
    // This means one is drawn to FBO1, then FBO1's result
    // is used to draw on FBO2, etc.
    if(m_ppfx)
    {
        // If there was lighting, the first texture is
        // the second FBO.
        CRenderTarget& One = m_lighting ? m_FBO2 : m_FBO1;
        CRenderTarget& Two = m_lighting ? m_FBO1 : m_FBO2;

        auto i = m_allPPFX.begin(),
             j = m_allPPFX.end();

        for(size_t c = 0; i != j; ++i, ++c)
        {
            auto& FX = *i;
            bool even = ((c & 0x1) == 0);
            if(even)    Two.Bind();
            else        One.Bind();

            FX->Enable();
            CRenderer::EnableTexture(final_texture);
            FS.Draw();
            FX->Disable();

            final_texture = even ? Two.GetTexture() : One.GetTexture();
        }
    }

    // Now we have the final scene data in `final_texture`

    // Doesn't matter which we disable.
    m_FBO1.Unbind();

    E.Enable();
    CRenderer::EnableTexture(final_texture);
    if(!m_through) CRenderer::BlendOperation(BlendFunc::DISABLE_BLEND);
    GL(glDisable(GL_DEPTH_TEST));

    // Make sure the right data is set.
    E.SetParameter("mv", math::matrix4x4_t::GetIdentityMatrix());
    E.SetParameter("proj", CRenderer::GetProjectionMatrix());

    FS.Draw();

    CRenderer::EnableTexture(0);
    CRenderer::ResetMaterialState();

    if(!blend && m_through) CRenderer::BlendOperation(BlendFunc::DISABLE_BLEND);

    return true;
}

int32_t CScene::GetEntityIndex(const obj::CEntity& D)
{
    int32_t index = -1;
    for(auto i : m_allEntities)
    {
        ++index;
        if(i == &D) return index;
    }

    return index;
}

bool CScene::IsValidEntityIndex(int32_t i)
{
    return (i > 0 && i < m_allEntities.size());
}
<|endoftext|>


<commit_before>#include "BinaryB4R.h"
#include "ImageIDer.h"
#include "Lzma.h"
#include "tools.h"

#include <easyimage.h>
#include <dtex_pvr.h>
#include <dtex_b4r.h>

namespace epbin
{

static const uint8_t TYPE = 14;

static const uint16_t TEX_PVR = 1;
static const uint16_t TEX_ETC1 = 2;

BinaryB4R::BinaryB4R(const std::vector<std::string>& src_files,
					 const std::string& img_id_file,
					 bool is_pvr)
	: m_is_pvr(is_pvr)
{
	LoadPictures(src_files, img_id_file);
}

BinaryB4R::~BinaryB4R()
{
	for_each(m_pics.begin(), m_pics.end(), DeletePointerFunctor<Picture>());
}

void BinaryB4R::Pack(const std::string& outfile, bool compress) const
{
	uint16_t pic_sz = m_pics.size();

	// data sz
	size_t data_sz = 0;
	data_sz += sizeof(int32_t);
	for (int i = 0; i < pic_sz; ++i) {
		data_sz += m_pics[i]->Size(m_is_pvr);
	}

	// fill buffer
	uint8_t* data_buf = new uint8_t[data_sz];
	uint8_t* ptr_data = data_buf;
	// store pic_sz
	memcpy(ptr_data, &pic_sz, sizeof(pic_sz));
	ptr_data += sizeof(pic_sz);
	// store tex type
	uint16_t type = m_is_pvr ? TEX_PVR : TEX_ETC1;
	memcpy(ptr_data, &type, sizeof(type));
	ptr_data += sizeof(type);
	// store pictures
	for (int i = 0; i < pic_sz; ++i) {
		m_pics[i]->Store(m_is_pvr, &ptr_data);
	}
	assert(ptr_data - data_buf == data_sz);

	// final
	size_t sz = data_sz + sizeof(uint8_t) + sizeof(uint32_t);
	uint8_t* buf = new uint8_t[sz];
	uint8_t* ptr = buf;
	memcpy(ptr, &TYPE, sizeof(uint8_t));
	ptr += sizeof(uint8_t);
	int cap = dtex_b4r_size(data_buf, data_sz);
	memcpy(ptr, &cap, sizeof(uint32_t));
	ptr += sizeof(uint32_t);
	memcpy(ptr, data_buf, data_sz);
	delete[] data_buf;

	// write to file
	std::ofstream fout(outfile.c_str(), std::ios::binary);
	if (compress)
	{
		uint8_t* dst = NULL;
		size_t dst_sz;
		Lzma::Compress(&dst, &dst_sz, buf, sz);

		fout.write(reinterpret_cast<const char*>(&dst_sz), sizeof(uint32_t));
		fout.write(reinterpret_cast<const char*>(dst), dst_sz);
	}
	else
	{
		int _sz = -(int)sz;
		fout.write(reinterpret_cast<const char*>(&_sz), sizeof(int32_t));
		fout.write(reinterpret_cast<const char*>(buf), sz);
	}
	delete[] buf;
	fout.close();
}

void BinaryB4R::LoadPictures(const std::vector<std::string>& src_files, const std::string& img_id_file)
{
	ImageIDer ider(img_id_file);
	for (int i = 0, n = src_files.size(); i < n; ++i)
	{
		wxString str;
		str.Printf("BinaryB4R load pic [%d/%d]\n", i, n);
		std::cout << str;

		const std::string& filepath = src_files[i];

		Picture* pic = CreatePicture(filepath);
		pic->id = ider.Query(filepath);
		m_pics.push_back(pic);
	}
}

BinaryB4R::Picture* BinaryB4R::CreatePicture(const std::string& filepath) const
{
	int sw, sh, sc, sf;
	uint8_t* src_pixels = eimage::ImageIO::Read(filepath.c_str(), sw, sh, sc, sf);

	// cut
	eimage::RegularRectCut cut(src_pixels, sw, sh);
	cut.AutoCut();

	// compress texture
	uint8_t* pixels;
	int w, h;
	if (m_is_pvr) {
		eimage::TransToPVR trans(src_pixels, sw, sh, sc);
		pixels = trans.GetPixelsData(w, h);
	} else {
		eimage::TransToETC1 trans(src_pixels, sw, sh, sc);
		pixels = trans.GetPixelsData(w, h);
	}

	// create pic
	Picture* pic = new Picture;

	pic->bmp_w = sw;
	pic->bmp_h = sh;
	pic->bmp_pixels = src_pixels;

	pic->path = filepath;

	pic->w = w;
	pic->h = h;
	size_t sz = m_is_pvr ? w * h * 0.5f : w * h;
	pic->compressed_pixels = new uint8_t[sz];
	memcpy(pic->compressed_pixels, pixels, sz);

	// flag data
	if (m_is_pvr) {
		assert(w == h && w % 4 == 0);
		int block = w >> 2;
		int block_sz = block * block;

		pic->flag_sz = std::ceil(block_sz / 8.0f);
		pic->flag = new uint8_t[pic->flag_sz];
		pic->block_used = 0;
		memset(pic->flag, 0, pic->flag_sz);
		int i = 0;
		for (int y = 0; y < block; ++y) {
			for (int x = 0; x < block; ++x) {
				if (!pic->IsBlockTransparent(x, y)) {
					pic->flag[i / 8] |= (1 << (i % 8));
					++pic->block_used;
				}
				++i;
			}
		}
	} else {
		assert(w % 4 == 0 && h % 4 == 0);
		int bw = w >> 2,
			bh = h >> 2;
		int block_sz = bw * bh;
		pic->flag_sz = std::ceil(block_sz / 8.0f);
		pic->flag = new uint8_t[pic->flag_sz];
		pic->block_used = 0;
		memset(pic->flag, 0, pic->flag_sz);
		int i = 0;
		for (int y = 0; y < bh; ++y) {
			for (int x = 0; x < bw; ++x) {
				if (!pic->IsBlockTransparent(x, y)) {
					pic->flag[i / 8] |= (1 << (i % 8));
					++pic->block_used;
				}
				++i;
			}
		}
	}

	return pic;
}

//////////////////////////////////////////////////////////////////////////
// class BinaryB4R::Picture
//////////////////////////////////////////////////////////////////////////

size_t BinaryB4R::Picture::
BlockSize(bool is_pvr)
{
	return is_pvr ? sizeof(int64_t) : sizeof(int64_t) * 2;
}

BinaryB4R::Picture::
~Picture()
{
	delete[] bmp_pixels;
	delete[] compressed_pixels;
	delete[] flag;
}

size_t BinaryB4R::Picture::
Size(bool is_pvr) const
{
	size_t sz = 0;

	sz += sizeof(int16_t) * 3;

	sz += flag_sz;
	sz += block_used * BlockSize(is_pvr);

	return sz;
}

void BinaryB4R::Picture::
Store(bool is_pvr, uint8_t** ptr)
{
	memcpy(*ptr, &id, sizeof(id));
	*ptr += sizeof(id);

	memcpy(*ptr, &bmp_w, sizeof(bmp_w));
	*ptr += sizeof(bmp_w);
	memcpy(*ptr, &bmp_h, sizeof(bmp_h));
	*ptr += sizeof(bmp_h);

	memcpy(*ptr, flag, flag_sz);
	*ptr += flag_sz;

	if (is_pvr) {
		int block = w >> 2;
		int i = 0;
		for (int y = 0; y < block; ++y) {
			for (int x = 0; x < block; ++x) {
				if (!IsBlockTransparent(x, y)) {
					assert(flag[i / 8] & (1 << (i % 8)));
					int idx = dtex_pvr_get_morton_number(x, y);
					int64_t* ptr_src = (int64_t*)compressed_pixels + idx;
					memcpy(*ptr, ptr_src, sizeof(int64_t));
					*ptr += sizeof(int64_t);
				}
				++i;
			}
		}
	} else {
		int bw = w >> 2,
			bh = h >> 2;
		int block_count = bw * bh;
		int i = 0;
		for (int y = 0; y < bh; ++y) {
			for (int x = 0; x < bw; ++x) {
				if (!IsBlockTransparent(x, y)) {
					assert(flag[i / 8] & (1 << (i % 8)));
					int idx = y * bw + x;

					int64_t* rgb_data = (int64_t*)compressed_pixels + idx;
					memcpy(*ptr, rgb_data, sizeof(int64_t));
					*ptr += sizeof(int64_t);

					int64_t* alpha_data = (int64_t*)compressed_pixels + block_count + idx;
					memcpy(*ptr, alpha_data, sizeof(int64_t));
					*ptr += sizeof(int64_t);
				}
				++i;
			}
		}
	}
}

bool BinaryB4R::Picture::
IsBlockTransparent(int x, int y) const
{
	return IsBMPBlockTransparent(x, y);
}

bool BinaryB4R::Picture::
IsPVRBlockTransparent(int x, int y) const
{
	int idx = dtex_pvr_get_morton_number(x, y);
	int64_t* ptr = (int64_t*)compressed_pixels + idx;
	return *((int32_t*)ptr) == 0xaaaaaaaa;
}

bool BinaryB4R::Picture::
IsBMPBlockTransparent(int x, int y) const
{
	for (int px = x * 4; px < x * 4 + 4; ++px) {
		for (int py = y * 4; py < y * 4 + 4; ++py) {
			if (px >= bmp_w || py >= bmp_h) {
				continue;
			}

			int _py = bmp_h - 1 - py;
			if (bmp_pixels[(bmp_w * _py + px) * 4 + 4 - 1] != 0) {
				return false;
			}
		}
	}

	return true;
}

}<commit_msg>[REMOVED] 生成b4r不需要RegularRectCut<commit_after>#include "BinaryB4R.h"
#include "ImageIDer.h"
#include "Lzma.h"
#include "tools.h"

#include <easyimage.h>
#include <dtex_pvr.h>
#include <dtex_b4r.h>

namespace epbin
{

static const uint8_t TYPE = 14;

static const uint16_t TEX_PVR = 1;
static const uint16_t TEX_ETC1 = 2;

BinaryB4R::BinaryB4R(const std::vector<std::string>& src_files,
					 const std::string& img_id_file,
					 bool is_pvr)
	: m_is_pvr(is_pvr)
{
	LoadPictures(src_files, img_id_file);
}

BinaryB4R::~BinaryB4R()
{
	for_each(m_pics.begin(), m_pics.end(), DeletePointerFunctor<Picture>());
}

void BinaryB4R::Pack(const std::string& outfile, bool compress) const
{
	uint16_t pic_sz = m_pics.size();

	// data sz
	size_t data_sz = 0;
	data_sz += sizeof(int32_t);
	for (int i = 0; i < pic_sz; ++i) {
		data_sz += m_pics[i]->Size(m_is_pvr);
	}

	// fill buffer
	uint8_t* data_buf = new uint8_t[data_sz];
	uint8_t* ptr_data = data_buf;
	// store pic_sz
	memcpy(ptr_data, &pic_sz, sizeof(pic_sz));
	ptr_data += sizeof(pic_sz);
	// store tex type
	uint16_t type = m_is_pvr ? TEX_PVR : TEX_ETC1;
	memcpy(ptr_data, &type, sizeof(type));
	ptr_data += sizeof(type);
	// store pictures
	for (int i = 0; i < pic_sz; ++i) {
		m_pics[i]->Store(m_is_pvr, &ptr_data);
	}
	assert(ptr_data - data_buf == data_sz);

	// final
	size_t sz = data_sz + sizeof(uint8_t) + sizeof(uint32_t);
	uint8_t* buf = new uint8_t[sz];
	uint8_t* ptr = buf;
	memcpy(ptr, &TYPE, sizeof(uint8_t));
	ptr += sizeof(uint8_t);
	int cap = dtex_b4r_size(data_buf, data_sz);
	memcpy(ptr, &cap, sizeof(uint32_t));
	ptr += sizeof(uint32_t);
	memcpy(ptr, data_buf, data_sz);
	delete[] data_buf;

	// write to file
	std::ofstream fout(outfile.c_str(), std::ios::binary);
	if (compress)
	{
		uint8_t* dst = NULL;
		size_t dst_sz;
		Lzma::Compress(&dst, &dst_sz, buf, sz);

		fout.write(reinterpret_cast<const char*>(&dst_sz), sizeof(uint32_t));
		fout.write(reinterpret_cast<const char*>(dst), dst_sz);
	}
	else
	{
		int _sz = -(int)sz;
		fout.write(reinterpret_cast<const char*>(&_sz), sizeof(int32_t));
		fout.write(reinterpret_cast<const char*>(buf), sz);
	}
	delete[] buf;
	fout.close();
}

void BinaryB4R::LoadPictures(const std::vector<std::string>& src_files, const std::string& img_id_file)
{
	ImageIDer ider(img_id_file);
	for (int i = 0, n = src_files.size(); i < n; ++i)
	{
		wxString str;
		str.Printf("BinaryB4R load pic [%d/%d]\n", i, n);
		std::cout << str;

		const std::string& filepath = src_files[i];

		Picture* pic = CreatePicture(filepath);
		pic->id = ider.Query(filepath);
		m_pics.push_back(pic);
	}
}

BinaryB4R::Picture* BinaryB4R::CreatePicture(const std::string& filepath) const
{
	int sw, sh, sc, sf;
	uint8_t* src_pixels = eimage::ImageIO::Read(filepath.c_str(), sw, sh, sc, sf);

// 	// cut
// 	eimage::RegularRectCut cut(src_pixels, sw, sh);
// 	cut.AutoCut();

	// compress texture
	uint8_t* pixels;
	int w, h;
	if (m_is_pvr) {
		eimage::TransToPVR trans(src_pixels, sw, sh, sc);
		pixels = trans.GetPixelsData(w, h);
	} else {
		eimage::TransToETC1 trans(src_pixels, sw, sh, sc);
		pixels = trans.GetPixelsData(w, h);
	}

	// create pic
	Picture* pic = new Picture;

	pic->bmp_w = sw;
	pic->bmp_h = sh;
	pic->bmp_pixels = src_pixels;

	pic->path = filepath;

	pic->w = w;
	pic->h = h;
	size_t sz = m_is_pvr ? w * h * 0.5f : w * h;
	pic->compressed_pixels = new uint8_t[sz];
	memcpy(pic->compressed_pixels, pixels, sz);

	// flag data
	if (m_is_pvr) {
		assert(w == h && w % 4 == 0);
		int block = w >> 2;
		int block_sz = block * block;

		pic->flag_sz = std::ceil(block_sz / 8.0f);
		pic->flag = new uint8_t[pic->flag_sz];
		pic->block_used = 0;
		memset(pic->flag, 0, pic->flag_sz);
		int i = 0;
		for (int y = 0; y < block; ++y) {
			for (int x = 0; x < block; ++x) {
				if (!pic->IsBlockTransparent(x, y)) {
					pic->flag[i / 8] |= (1 << (i % 8));
					++pic->block_used;
				}
				++i;
			}
		}
	} else {
		assert(w % 4 == 0 && h % 4 == 0);
		int bw = w >> 2,
			bh = h >> 2;
		int block_sz = bw * bh;
		pic->flag_sz = std::ceil(block_sz / 8.0f);
		pic->flag = new uint8_t[pic->flag_sz];
		pic->block_used = 0;
		memset(pic->flag, 0, pic->flag_sz);
		int i = 0;
		for (int y = 0; y < bh; ++y) {
			for (int x = 0; x < bw; ++x) {
				if (!pic->IsBlockTransparent(x, y)) {
					pic->flag[i / 8] |= (1 << (i % 8));
					++pic->block_used;
				}
				++i;
			}
		}
	}

	return pic;
}

//////////////////////////////////////////////////////////////////////////
// class BinaryB4R::Picture
//////////////////////////////////////////////////////////////////////////

size_t BinaryB4R::Picture::
BlockSize(bool is_pvr)
{
	return is_pvr ? sizeof(int64_t) : sizeof(int64_t) * 2;
}

BinaryB4R::Picture::
~Picture()
{
	delete[] bmp_pixels;
	delete[] compressed_pixels;
	delete[] flag;
}

size_t BinaryB4R::Picture::
Size(bool is_pvr) const
{
	size_t sz = 0;

	sz += sizeof(int16_t) * 3;

	sz += flag_sz;
	sz += block_used * BlockSize(is_pvr);

	return sz;
}

void BinaryB4R::Picture::
Store(bool is_pvr, uint8_t** ptr)
{
	memcpy(*ptr, &id, sizeof(id));
	*ptr += sizeof(id);

	memcpy(*ptr, &bmp_w, sizeof(bmp_w));
	*ptr += sizeof(bmp_w);
	memcpy(*ptr, &bmp_h, sizeof(bmp_h));
	*ptr += sizeof(bmp_h);

	memcpy(*ptr, flag, flag_sz);
	*ptr += flag_sz;

	if (is_pvr) {
		int block = w >> 2;
		int i = 0;
		for (int y = 0; y < block; ++y) {
			for (int x = 0; x < block; ++x) {
				if (!IsBlockTransparent(x, y)) {
					assert(flag[i / 8] & (1 << (i % 8)));
					int idx = dtex_pvr_get_morton_number(x, y);
					int64_t* ptr_src = (int64_t*)compressed_pixels + idx;
					memcpy(*ptr, ptr_src, sizeof(int64_t));
					*ptr += sizeof(int64_t);
				}
				++i;
			}
		}
	} else {
		int bw = w >> 2,
			bh = h >> 2;
		int block_count = bw * bh;
		int i = 0;
		for (int y = 0; y < bh; ++y) {
			for (int x = 0; x < bw; ++x) {
				if (!IsBlockTransparent(x, y)) {
					assert(flag[i / 8] & (1 << (i % 8)));
					int idx = y * bw + x;

					int64_t* rgb_data = (int64_t*)compressed_pixels + idx;
					memcpy(*ptr, rgb_data, sizeof(int64_t));
					*ptr += sizeof(int64_t);

					int64_t* alpha_data = (int64_t*)compressed_pixels + block_count + idx;
					memcpy(*ptr, alpha_data, sizeof(int64_t));
					*ptr += sizeof(int64_t);
				}
				++i;
			}
		}
	}
}

bool BinaryB4R::Picture::
IsBlockTransparent(int x, int y) const
{
	return IsBMPBlockTransparent(x, y);
}

bool BinaryB4R::Picture::
IsPVRBlockTransparent(int x, int y) const
{
	int idx = dtex_pvr_get_morton_number(x, y);
	int64_t* ptr = (int64_t*)compressed_pixels + idx;
	return *((int32_t*)ptr) == 0xaaaaaaaa;
}

bool BinaryB4R::Picture::
IsBMPBlockTransparent(int x, int y) const
{
	for (int px = x * 4; px < x * 4 + 4; ++px) {
		for (int py = y * 4; py < y * 4 + 4; ++py) {
			if (px >= bmp_w || py >= bmp_h) {
				continue;
			}

			int _py = bmp_h - 1 - py;
			if (bmp_pixels[(bmp_w * _py + px) * 4 + 4 - 1] != 0) {
				return false;
			}
		}
	}

	return true;
}

}<|endoftext|>


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

#include "config.h"
#include "core/platform/graphics/FontPlatformData.h"

#include <windows.h>
#include <mlang.h>
#include <objidl.h>
#include "core/platform/LayoutTestSupport.h"
#include "platform/SharedBuffer.h"
#include "core/platform/graphics/FontCache.h"
#include "core/platform/graphics/GraphicsContext.h"
#include "core/platform/graphics/skia/SkiaFontWin.h"
#include "core/platform/win/HWndDC.h"
#include "public/platform/Platform.h"
#include "public/platform/win/WebSandboxSupport.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/ports/SkTypeface_win.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/StdLibExtras.h"

namespace WebCore {

void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext* context) const
{
    const float ts = m_textSize >= 0 ? m_textSize : 12;
    paint->setTextSize(SkFloatToScalar(m_textSize));
    paint->setTypeface(typeface());
    paint->setFakeBoldText(m_fakeBold);
    paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0);

    // Only set painting flags when we're actually painting.
    if (context) {
        int textFlags = paintTextFlags();
        if (!context->couldUseLCDRenderedText()) {
            textFlags &= ~SkPaint::kLCDRenderText_Flag;
            // If we *just* clear our request for LCD, then GDI seems to
            // sometimes give us AA text, and sometimes give us BW text. Since the
            // original intent was LCD, we want to force AA (rather than BW), so we
            // add a special bit to tell Skia to do its best to avoid the BW: by
            // drawing LCD offscreen and downsampling that to AA.
            textFlags |= SkPaint::kGenA8FromLCD_Flag;
        }

        static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag |
            SkPaint::kLCDRenderText_Flag |
            SkPaint::kGenA8FromLCD_Flag;

        SkASSERT(!(textFlags & ~textFlagsMask));
        uint32_t flags = paint->getFlags();
        flags &= ~textFlagsMask;
        flags |= textFlags;
        paint->setFlags(flags);
    }
}

// Lookup the current system settings for font smoothing.
// We cache these values for performance, but if the browser has a way to be
// notified when these change, we could re-query them at that time.
static uint32_t getDefaultGDITextFlags()
{
    static bool gInited;
    static uint32_t gFlags;
    if (!gInited) {
        BOOL enabled;
        gFlags = 0;
        if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) {
            gFlags |= SkPaint::kAntiAlias_Flag;

            UINT smoothType;
            if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) {
                if (FE_FONTSMOOTHINGCLEARTYPE == smoothType)
                    gFlags |= SkPaint::kLCDRenderText_Flag;
            }
        }
        gInited = true;
    }
    return gFlags;
}

static bool isWebFont(const LOGFONT& lf)
{
    // web-fonts have artifical names constructed to always be
    // 1. 24 characters, followed by a '\0'
    // 2. the last two characters are '=='
    return '=' == lf.lfFaceName[22] && '=' == lf.lfFaceName[23] && '\0' == lf.lfFaceName[24];
}

static int computePaintTextFlags(const LOGFONT& lf)
{
    int textFlags = 0;
    switch (lf.lfQuality) {
    case NONANTIALIASED_QUALITY:
        textFlags = 0;
        break;
    case ANTIALIASED_QUALITY:
        textFlags = SkPaint::kAntiAlias_Flag;
        break;
    case CLEARTYPE_QUALITY:
        textFlags = (SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag);
        break;
    default:
        textFlags = getDefaultGDITextFlags();
        break;
    }

    // only allow features that SystemParametersInfo allows
    textFlags &= getDefaultGDITextFlags();

    /*
     *  FontPlatformData(...) will read our logfont, and try to honor the the lfQuality
     *  setting (computing the corresponding SkPaint flags for AA and LCD). However, it
     *  will limit the quality based on its query of SPI_GETFONTSMOOTHING. This could mean
     *  we end up drawing the text in BW, even though our lfQuality requested antialiasing.
     *
     *  Many web-fonts are so poorly hinted that they are terrible to read when drawn in BW.
     *  In these cases, we have decided to FORCE these fonts to be drawn with at least grayscale AA,
     *  even when the System (getDefaultGDITextFlags) tells us to draw only in BW.
     */
    if (isWebFont(lf) && !isRunningLayoutTest())
        textFlags |= SkPaint::kAntiAlias_Flag;
    return textFlags;
}

PassRefPtr<SkTypeface> CreateTypefaceFromHFont(HFONT hfont, int* size, int* paintTextFlags)
{
    LOGFONT info;
    GetObject(hfont, sizeof(info), &info);
    if (size) {
        int height = info.lfHeight;
        if (height < 0)
            height = -height;
        *size = height;
    }
    if (paintTextFlags)
        *paintTextFlags = computePaintTextFlags(info);
    return adoptRef(SkCreateTypefaceFromLOGFONT(info));
}

FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
    : m_font(0)
    , m_textSize(-1)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(true)
{
}

FontPlatformData::FontPlatformData()
    : m_font(0)
    , m_textSize(0)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(HFONT font, float size, FontOrientation orientation)
    : m_font(RefCountedHFONT::create(font))
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(CreateTypefaceFromHFont(font, 0, &m_paintTextFlags))
    , m_isHashTableDeletedValue(false)
{
}

// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
    : m_font(0)
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data)
    : m_font(data.m_font)
    , m_textSize(data.m_textSize)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data, float textSize)
    : m_font(data.m_font)
    , m_textSize(textSize)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation)
    : m_font(0)
    , m_textSize(textSize)
    , m_fakeBold(fakeBold)
    , m_fakeItalic(fakeItalic)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(tf)
    , m_isHashTableDeletedValue(false)
{
    // FIXME: This can be removed together with m_font once the last few
    // uses of hfont() has been eliminated.
    LOGFONT logFont;
    SkLOGFONTFromTypeface(tf, &logFont);
    logFont.lfHeight = -textSize;
    HFONT hFont = CreateFontIndirect(&logFont);
    if (hFont)
        m_font = RefCountedHFONT::create(hFont);
    m_paintTextFlags = computePaintTextFlags(logFont);
}

FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data)
{
    if (this != &data) {
        m_font = data.m_font;
        m_textSize = data.m_textSize;
        m_fakeBold = data.m_fakeBold;
        m_fakeItalic = data.m_fakeItalic;
        m_orientation = data.m_orientation;
        m_typeface = data.m_typeface;
        m_paintTextFlags = data.m_paintTextFlags;

        // The following fields will get re-computed if necessary.
        ScriptFreeCache(&m_scriptCache);
        m_scriptCache = 0;
        m_scriptFontProperties.clear();
    }
    return *this;
}

FontPlatformData::~FontPlatformData()
{
    ScriptFreeCache(&m_scriptCache);
    m_scriptCache = 0;
}

String FontPlatformData::fontFamilyName() const
{
    HWndDC dc(0);
    HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont()));
    WCHAR name[LF_FACESIZE];
    unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name);
    if (resultLength > 0)
        resultLength--; // ignore the null terminator
    SelectObject(dc, oldFont);
    return String(name, resultLength);
}

bool FontPlatformData::isFixedPitch() const
{
#if ENABLE(GDI_FONTS_ON_WINDOWS)
    // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
    HWndDC dc(0);
    HGDIOBJ oldFont = SelectObject(dc, hfont());

    // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
    // is *not* fixed pitch. Unbelievable but true.
    TEXTMETRIC textMetric = { 0 };
    if (!GetTextMetrics(dc, &textMetric)) {
        if (ensureFontLoaded(hfont())) {
            // Retry GetTextMetrics.
            // FIXME: Handle gracefully the error if this call also fails.
            // See http://crbug.com/6401.
            if (!GetTextMetrics(dc, &textMetric))
                LOG_ERROR("Unable to get the text metrics after second attempt");
        }
    }

    bool treatAsFixedPitch = !(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH);

    SelectObject(dc, oldFont);

    return treatAsFixedPitch;
#else
    return typeface() && typeface()->isFixedPitch();
#endif
}

FontPlatformData::RefCountedHFONT::~RefCountedHFONT()
{
    DeleteObject(m_hfont);
}

SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
{
    if (!m_scriptFontProperties) {
        m_scriptFontProperties = adoptPtr(new SCRIPT_FONTPROPERTIES);
        memset(m_scriptFontProperties.get(), 0, sizeof(SCRIPT_FONTPROPERTIES));
        m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
        HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties.get());
        if (result == E_PENDING) {
            HWndDC dc(0);
            HGDIOBJ oldFont = SelectObject(dc, hfont());
            HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
            if (S_OK != hr) {
                if (FontPlatformData::ensureFontLoaded(hfont())) {
                    // FIXME: Handle gracefully the error if this call also fails.
                    hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
                    if (S_OK != hr) {
                        LOG_ERROR("Unable to get the font properties after second attempt");
                    }
                }
            }

            SelectObject(dc, oldFont);
        }
    }
    return m_scriptFontProperties.get();
}

#ifndef NDEBUG
String FontPlatformData::description() const
{
    return String();
}
#endif

bool FontPlatformData::ensureFontLoaded(HFONT font)
{
    WebKit::WebSandboxSupport* sandboxSupport = WebKit::Platform::current()->sandboxSupport();
    // if there is no sandbox, then we can assume the font
    // was able to be loaded successfully already
    return sandboxSupport ? sandboxSupport->ensureFontLoaded(font) : true;
}

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

#include "config.h"
#include "core/platform/graphics/FontPlatformData.h"

#include <windows.h>
#include <mlang.h>
#include <objidl.h>
#include "core/platform/LayoutTestSupport.h"
#include "platform/SharedBuffer.h"
#include "core/platform/graphics/FontCache.h"
#include "core/platform/graphics/GraphicsContext.h"
#include "core/platform/graphics/skia/SkiaFontWin.h"
#include "core/platform/win/HWndDC.h"
#include "public/platform/Platform.h"
#include "public/platform/win/WebSandboxSupport.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/ports/SkTypeface_win.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/StdLibExtras.h"

namespace WebCore {

void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext* context) const
{
    const float ts = m_textSize >= 0 ? m_textSize : 12;
    paint->setTextSize(SkFloatToScalar(m_textSize));
    paint->setTypeface(typeface());
    paint->setFakeBoldText(m_fakeBold);
    paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0);

    // Only set painting flags when we're actually painting.
    if (context) {
        int textFlags = paintTextFlags();
        if (!context->couldUseLCDRenderedText()) {
            textFlags &= ~SkPaint::kLCDRenderText_Flag;
            // If we *just* clear our request for LCD, then GDI seems to
            // sometimes give us AA text, and sometimes give us BW text. Since the
            // original intent was LCD, we want to force AA (rather than BW), so we
            // add a special bit to tell Skia to do its best to avoid the BW: by
            // drawing LCD offscreen and downsampling that to AA.
            textFlags |= SkPaint::kGenA8FromLCD_Flag;
        }

        static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag |
            SkPaint::kLCDRenderText_Flag |
            SkPaint::kGenA8FromLCD_Flag;

        SkASSERT(!(textFlags & ~textFlagsMask));
        uint32_t flags = paint->getFlags();
        flags &= ~textFlagsMask;
        flags |= textFlags;
        paint->setFlags(flags);
    }
}

// Lookup the current system settings for font smoothing.
// We cache these values for performance, but if the browser has a way to be
// notified when these change, we could re-query them at that time.
static uint32_t getDefaultGDITextFlags()
{
    static bool gInited;
    static uint32_t gFlags;
    if (!gInited) {
        BOOL enabled;
        gFlags = 0;
        if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) {
            gFlags |= SkPaint::kAntiAlias_Flag;

            UINT smoothType;
            if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) {
                if (FE_FONTSMOOTHINGCLEARTYPE == smoothType)
                    gFlags |= SkPaint::kLCDRenderText_Flag;
            }
        }
        gInited = true;
    }
    return gFlags;
}

static bool isWebFont(const LOGFONT& lf)
{
    // web-fonts have artifical names constructed to always be
    // 1. 24 characters, followed by a '\0'
    // 2. the last two characters are '=='
    return '=' == lf.lfFaceName[22] && '=' == lf.lfFaceName[23] && '\0' == lf.lfFaceName[24];
}

static int computePaintTextFlags(const LOGFONT& lf)
{
    int textFlags = 0;
    switch (lf.lfQuality) {
    case NONANTIALIASED_QUALITY:
        textFlags = 0;
        break;
    case ANTIALIASED_QUALITY:
        textFlags = SkPaint::kAntiAlias_Flag;
        break;
    case CLEARTYPE_QUALITY:
        textFlags = (SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag);
        break;
    default:
        textFlags = getDefaultGDITextFlags();
        break;
    }

    // only allow features that SystemParametersInfo allows
    textFlags &= getDefaultGDITextFlags();

    /*
     *  FontPlatformData(...) will read our logfont, and try to honor the the lfQuality
     *  setting (computing the corresponding SkPaint flags for AA and LCD). However, it
     *  will limit the quality based on its query of SPI_GETFONTSMOOTHING. This could mean
     *  we end up drawing the text in BW, even though our lfQuality requested antialiasing.
     *
     *  Many web-fonts are so poorly hinted that they are terrible to read when drawn in BW.
     *  In these cases, we have decided to FORCE these fonts to be drawn with at least grayscale AA,
     *  even when the System (getDefaultGDITextFlags) tells us to draw only in BW.
     */
    if (isWebFont(lf) && !isRunningLayoutTest())
        textFlags |= SkPaint::kAntiAlias_Flag;
    return textFlags;
}

PassRefPtr<SkTypeface> CreateTypefaceFromHFont(HFONT hfont, int* size, int* paintTextFlags)
{
    LOGFONT info;
    GetObject(hfont, sizeof(info), &info);
    if (size) {
        int height = info.lfHeight;
        if (height < 0)
            height = -height;
        *size = height;
    }
    if (paintTextFlags)
        *paintTextFlags = computePaintTextFlags(info);
    return adoptRef(SkCreateTypefaceFromLOGFONT(info));
}

FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
    : m_font(0)
    , m_textSize(-1)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(true)
{
}

FontPlatformData::FontPlatformData()
    : m_font(0)
    , m_textSize(0)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(HFONT font, float size, FontOrientation orientation)
    : m_font(RefCountedHFONT::create(font))
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(CreateTypefaceFromHFont(font, 0, &m_paintTextFlags))
    , m_isHashTableDeletedValue(false)
{
}

// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
    : m_font(0)
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data)
    : m_font(data.m_font)
    , m_textSize(data.m_textSize)
    , m_fakeBold(data.m_fakeBold)
    , m_fakeItalic(data.m_fakeItalic)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data, float textSize)
    : m_font(data.m_font)
    , m_textSize(textSize)
    , m_fakeBold(data.m_fakeBold)
    , m_fakeItalic(data.m_fakeItalic)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation)
    : m_font(0)
    , m_textSize(textSize)
    , m_fakeBold(fakeBold)
    , m_fakeItalic(fakeItalic)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(tf)
    , m_isHashTableDeletedValue(false)
{
    // FIXME: This can be removed together with m_font once the last few
    // uses of hfont() has been eliminated.
    LOGFONT logFont;
    SkLOGFONTFromTypeface(tf, &logFont);
    logFont.lfHeight = -textSize;
    HFONT hFont = CreateFontIndirect(&logFont);
    if (hFont)
        m_font = RefCountedHFONT::create(hFont);
    m_paintTextFlags = computePaintTextFlags(logFont);
}

FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data)
{
    if (this != &data) {
        m_font = data.m_font;
        m_textSize = data.m_textSize;
        m_fakeBold = data.m_fakeBold;
        m_fakeItalic = data.m_fakeItalic;
        m_orientation = data.m_orientation;
        m_typeface = data.m_typeface;
        m_paintTextFlags = data.m_paintTextFlags;

        // The following fields will get re-computed if necessary.
        ScriptFreeCache(&m_scriptCache);
        m_scriptCache = 0;
        m_scriptFontProperties.clear();
    }
    return *this;
}

FontPlatformData::~FontPlatformData()
{
    ScriptFreeCache(&m_scriptCache);
    m_scriptCache = 0;
}

String FontPlatformData::fontFamilyName() const
{
    HWndDC dc(0);
    HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont()));
    WCHAR name[LF_FACESIZE];
    unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name);
    if (resultLength > 0)
        resultLength--; // ignore the null terminator
    SelectObject(dc, oldFont);
    return String(name, resultLength);
}

bool FontPlatformData::isFixedPitch() const
{
#if ENABLE(GDI_FONTS_ON_WINDOWS)
    // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
    HWndDC dc(0);
    HGDIOBJ oldFont = SelectObject(dc, hfont());

    // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
    // is *not* fixed pitch. Unbelievable but true.
    TEXTMETRIC textMetric = { 0 };
    if (!GetTextMetrics(dc, &textMetric)) {
        if (ensureFontLoaded(hfont())) {
            // Retry GetTextMetrics.
            // FIXME: Handle gracefully the error if this call also fails.
            // See http://crbug.com/6401.
            if (!GetTextMetrics(dc, &textMetric))
                LOG_ERROR("Unable to get the text metrics after second attempt");
        }
    }

    bool treatAsFixedPitch = !(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH);

    SelectObject(dc, oldFont);

    return treatAsFixedPitch;
#else
    return typeface() && typeface()->isFixedPitch();
#endif
}

FontPlatformData::RefCountedHFONT::~RefCountedHFONT()
{
    DeleteObject(m_hfont);
}

SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
{
    if (!m_scriptFontProperties) {
        m_scriptFontProperties = adoptPtr(new SCRIPT_FONTPROPERTIES);
        memset(m_scriptFontProperties.get(), 0, sizeof(SCRIPT_FONTPROPERTIES));
        m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
        HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties.get());
        if (result == E_PENDING) {
            HWndDC dc(0);
            HGDIOBJ oldFont = SelectObject(dc, hfont());
            HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
            if (S_OK != hr) {
                if (FontPlatformData::ensureFontLoaded(hfont())) {
                    // FIXME: Handle gracefully the error if this call also fails.
                    hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
                    if (S_OK != hr) {
                        LOG_ERROR("Unable to get the font properties after second attempt");
                    }
                }
            }

            SelectObject(dc, oldFont);
        }
    }
    return m_scriptFontProperties.get();
}

#ifndef NDEBUG
String FontPlatformData::description() const
{
    return String();
}
#endif

bool FontPlatformData::ensureFontLoaded(HFONT font)
{
    WebKit::WebSandboxSupport* sandboxSupport = WebKit::Platform::current()->sandboxSupport();
    // if there is no sandbox, then we can assume the font
    // was able to be loaded successfully already
    return sandboxSupport ? sandboxSupport->ensureFontLoaded(font) : true;
}

}
<|endoftext|>


<commit_before><commit_msg>584 - Bowling<commit_after><|endoftext|>