<commit_before>#include <iostream>
#include <algorithm>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string>
#include <cstring>
#include <list>

#include <Project.h>
#include <Note.h>
#include <Colors.h>
#include <TableView.h>

#include <rhash.h>

struct timespec _tick_start;
struct timespec _tick_stop;

#define INIT_TIC_TAC()    { clock_gettime ( CLOCK_REALTIME, &_tick_start ); }

#define TIC( a )          {                                                    \
        clock_gettime ( CLOCK_REALTIME, &_tick_stop );                         \
        timespec diff;                                                         \
        diff.tv_sec  = _tick_stop.tv_sec - _tick_start.tv_sec;                 \
        diff.tv_nsec = _tick_stop.tv_nsec - _tick_start.tv_nsec;               \
        if ( diff.tv_nsec < 0 ) {                                              \
            diff.tv_sec  -= 1;                                                 \
            diff.tv_nsec += 1e9;                                               \
        }                                                                      \
        printf ( "%s: %lu s, %.2f ms\n", a, diff.tv_sec, diff.tv_nsec / 1e6 ); \
}

// List of supported commands.
typedef enum _MainCommands
{
    MC_ADD,
    MC_EDIT,
    MC_VIEW,
    MC_LIST,
    MC_DELETE,
    MC_NUM
} MainCommands;
const char * commands[] =
{
    "add",
    "edit",
    "view",
    "list",
    "delete",
    nullptr
};

/**
 * This project is written in C++, but tries to stick closer to C.
 * Classes, list, strings are ok.. Templates are already doubtful.
 */

// The Main object, this is also the root node.
class NotesCC : public Project
{
private:
    unsigned int      last_note_id = 0;
    std::string       db_path;
// Root project.
    std::list<Note *> notes;

public:
    static bool notes_sort ( Note *a, Note *b )
    {
        int time = ( a->get_time_t () - b->get_time_t () );
        if ( time == 0 ) {
            return a->get_title ().compare ( b->get_title () ) < 0;
            // TODO sort on filename last resort, so we get a stable sort.
        }
        return time < 0;
    }
    NotesCC( const char *path ) : Project ( "" )
    {
        db_path = path;

        this->Load ( this, "" );

        this->notes.sort ( notes_sort );
        for ( auto note : this->notes ) {
            note->set_id ( ++this->last_note_id );
        }
    }
    ~NotesCC()
    {
        for ( auto note : notes ) {
            delete note;
        }
    }

    void print_projects ()
    {
        this->print ();
    }

    std::string get_path ()
    {
        return db_path;
    }

    int autocomplete ( int argc, char **argv )
    {
        if ( argc == 0 ) {
            // List commands.
            for ( int i = 0; commands[i] != nullptr; i++ ) {
                std::cout << commands[i] << std::endl;
            }
            return 0;
        }
        this->list_projects ();

        return 1;
    }

    void run ( int argc, char **argv )
    {
        int index = 1;
        while ( index < argc ) {
            if ( strcmp ( argv[index], "--complete" ) == 0 ) {
                index++;
                index += this->autocomplete ( argc - index, &argv[index] );
            }
            else if ( strcmp ( argv[index], "list" ) == 0 ) {
                TableView view;

                // Add the columns
                view.add_column ( "ID", color_bold );
                view.add_column ( "Project", color_white_bold );
                view.add_column ( "Last edited", color_blue );
                view.add_column ( "CRC", color_red );
                view.add_column ( "Description" );
                for ( auto note : notes ) {
                    unsigned int row_index = note->get_id () - 1;
                    view[0].set_value ( row_index, std::to_string ( note->get_id () ) );
                    view[1].set_value ( row_index, note->get_project () );
                    view[2].set_value ( row_index, note->get_modtime () );
                    view[3].set_value ( row_index, std::to_string ( note->get_body_crc () ) );
                    view[4].set_value ( row_index, note->get_title () );
                    view++;
                }
                view.print ();
                index++;
            }
            else {
                std::cerr << "Invalid argument: " << argv[index] << std::endl;
                return;
            }
        }
    }

private:
    void Load ( Project *node, std::string path )
    {
        DIR *dir = opendir ( ( db_path + path ).c_str () );
        if ( dir != NULL ) {
            struct dirent *dirp;
            while ( ( dirp = readdir ( dir ) ) != NULL ) {
                // Skip hidden files (for now)
                if ( dirp->d_name[0] == '.' ) {
                    continue;
                }
                // Project
                if ( dirp->d_type == DT_DIR ) {
                    Project *p = new Project ( dirp->d_name );
                    node->add_subproject ( p );

                    // Recurse down in the structure.
                    std::string np = path + "/" + dirp->d_name;
                    Load ( p, np );
                }
                // Note
                else if ( dirp->d_type == DT_REG ) {
                    Note *note = new Note ( node, dirp->d_name );
                    // Add to the flat list in the main.
                    this->notes.push_back ( note );
                    node->add_note ( note );
                }
            }
            closedir ( dir );
        }
    }
};

int main ( int argc, char ** argv )
{
    char *path = NULL;

    rhash_library_init ();

    if ( asprintf ( &path, "%s/Notes2/", getenv ( "HOME" ) ) == -1 ) {
        fprintf ( stderr, "Failed to get path\n" );
        return EXIT_FAILURE;
    }
    INIT_TIC_TAC ()
    NotesCC notes ( path );

    notes.run ( argc, argv );

    TIC ( "finish" );
    free ( path );
    return EXIT_SUCCESS;
}
<commit_msg>Measure setup of rhash (1ms)<commit_after>#include <iostream>
#include <algorithm>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string>
#include <cstring>
#include <list>

#include <Project.h>
#include <Note.h>
#include <Colors.h>
#include <TableView.h>

#include <rhash.h>

struct timespec _tick_start;
struct timespec _tick_stop;

#define INIT_TIC_TAC()    { clock_gettime ( CLOCK_REALTIME, &_tick_start ); }

#define TIC( a )          {                                                    \
        clock_gettime ( CLOCK_REALTIME, &_tick_stop );                         \
        timespec diff;                                                         \
        diff.tv_sec  = _tick_stop.tv_sec - _tick_start.tv_sec;                 \
        diff.tv_nsec = _tick_stop.tv_nsec - _tick_start.tv_nsec;               \
        if ( diff.tv_nsec < 0 ) {                                              \
            diff.tv_sec  -= 1;                                                 \
            diff.tv_nsec += 1e9;                                               \
        }                                                                      \
        printf ( "%s: %lu s, %.2f ms\n", a, diff.tv_sec, diff.tv_nsec / 1e6 ); \
}

// List of supported commands.
typedef enum _MainCommands
{
    MC_ADD,
    MC_EDIT,
    MC_VIEW,
    MC_LIST,
    MC_DELETE,
    MC_NUM
} MainCommands;
const char * commands[] =
{
    "add",
    "edit",
    "view",
    "list",
    "delete",
    nullptr
};

/**
 * This project is written in C++, but tries to stick closer to C.
 * Classes, list, strings are ok.. Templates are already doubtful.
 */

// The Main object, this is also the root node.
class NotesCC : public Project
{
private:
    unsigned int      last_note_id = 0;
    std::string       db_path;
// Root project.
    std::list<Note *> notes;

public:
    static bool notes_sort ( Note *a, Note *b )
    {
        int time = ( a->get_time_t () - b->get_time_t () );
        if ( time == 0 ) {
            return a->get_title ().compare ( b->get_title () ) < 0;
            // TODO sort on filename last resort, so we get a stable sort.
        }
        return time < 0;
    }
    NotesCC( const char *path ) : Project ( "" )
    {
        db_path = path;

        this->Load ( this, "" );

        this->notes.sort ( notes_sort );
        for ( auto note : this->notes ) {
            note->set_id ( ++this->last_note_id );
        }
    }
    ~NotesCC()
    {
        for ( auto note : notes ) {
            delete note;
        }
    }

    void print_projects ()
    {
        this->print ();
    }

    std::string get_path ()
    {
        return db_path;
    }

    int autocomplete ( int argc, char **argv )
    {
        if ( argc == 0 ) {
            // List commands.
            for ( int i = 0; commands[i] != nullptr; i++ ) {
                std::cout << commands[i] << std::endl;
            }
            return 0;
        }
        this->list_projects ();

        return 1;
    }

    void run ( int argc, char **argv )
    {
        int index = 1;
        while ( index < argc ) {
            if ( strcmp ( argv[index], "--complete" ) == 0 ) {
                index++;
                index += this->autocomplete ( argc - index, &argv[index] );
            }
            else if ( strcmp ( argv[index], "list" ) == 0 ) {
                TableView view;

                // Add the columns
                view.add_column ( "ID", color_bold );
                view.add_column ( "Project", color_white_bold );
                view.add_column ( "Last edited", color_blue );
                view.add_column ( "CRC", color_red );
                view.add_column ( "Description" );
                for ( auto note : notes ) {
                    unsigned int row_index = note->get_id () - 1;
                    view[0].set_value ( row_index, std::to_string ( note->get_id () ) );
                    view[1].set_value ( row_index, note->get_project () );
                    view[2].set_value ( row_index, note->get_modtime () );
                    view[3].set_value ( row_index, std::to_string ( note->get_body_crc () ) );
                    view[4].set_value ( row_index, note->get_title () );
                    view++;
                }
                view.print ();
                index++;
            }
            else {
                std::cerr << "Invalid argument: " << argv[index] << std::endl;
                return;
            }
        }
    }

private:
    void Load ( Project *node, std::string path )
    {
        DIR *dir = opendir ( ( db_path + path ).c_str () );
        if ( dir != NULL ) {
            struct dirent *dirp;
            while ( ( dirp = readdir ( dir ) ) != NULL ) {
                // Skip hidden files (for now)
                if ( dirp->d_name[0] == '.' ) {
                    continue;
                }
                // Project
                if ( dirp->d_type == DT_DIR ) {
                    Project *p = new Project ( dirp->d_name );
                    node->add_subproject ( p );

                    // Recurse down in the structure.
                    std::string np = path + "/" + dirp->d_name;
                    Load ( p, np );
                }
                // Note
                else if ( dirp->d_type == DT_REG ) {
                    Note *note = new Note ( node, dirp->d_name );
                    // Add to the flat list in the main.
                    this->notes.push_back ( note );
                    node->add_note ( note );
                }
            }
            closedir ( dir );
        }
    }
};

int main ( int argc, char ** argv )
{
    char *path = NULL;
    INIT_TIC_TAC ()

    rhash_library_init ();

    TIC ( "RHash" );

    if ( asprintf ( &path, "%s/Notes2/", getenv ( "HOME" ) ) == -1 ) {
        fprintf ( stderr, "Failed to get path\n" );
        return EXIT_FAILURE;
    }
    NotesCC notes ( path );

    notes.run ( argc, argv );

    free ( path );
    TIC ( "finish" );
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <iostream>
#include <qitype/genericobject.hpp>
#include "object_p.hpp"

namespace qi {

  GenericObject::GenericObject(ObjectType *type, void *value)
  : type(type)
  , value(value)
  {
  }

  GenericObject::~GenericObject() {
  }

  Manageable::Manageable()
  {
    _p = new ManageablePrivate();
    _p->eventLoop = getDefaultObjectEventLoop();
    _p->dying = false;
  }

  Manageable::Manageable(const Manageable& b)
  {
    _p = new ManageablePrivate();
    _p->eventLoop = b._p->eventLoop;
    _p->dying = false;
  }

  void Manageable::operator = (const Manageable& b)
  {
    this->~Manageable();
    _p = new ManageablePrivate();
    _p->eventLoop = b._p->eventLoop;
    _p->dying = false;
  }

  Manageable::~Manageable()
  {
    _p->dying = true;
    std::vector<SignalSubscriber> copy;
    {
      boost::mutex::scoped_lock sl(_p->registrationsMutex);
      copy = _p->registrations;
    }
    for (unsigned i = 0; i < copy.size(); ++i)
    {
      copy[i].source->disconnect(copy[i].linkId);
    }
    delete _p;
  }

  void Manageable::moveToEventLoop(EventLoop* el)
  {
    _p->eventLoop = el;
  }

  EventLoop* Manageable::eventLoop() const
  {
    return _p->eventLoop;
  }

  const MetaObject &GenericObject::metaObject() {
    if (!type || !value) {
      static qi::MetaObject fail;
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return fail;
    }
    return type->metaObject(value);
  }

  qi::Future<GenericValue>
  GenericObject::metaCall(unsigned int method, const GenericFunctionParameters& params, MetaCallType callType)
  {
    qi::Promise<GenericValue> out;
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      out.setError("Invalid object");
      return out.future();
    }
    try {
      return type->metaCall(value, method, params, callType);
    } catch (std::runtime_error &e) {
      out.setError(e.what());
      return out.future();
    }
  }

  void GenericObject::metaEmit(unsigned int event, const GenericFunctionParameters& args)
  {
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return;
    }
    type->metaEmit(value, event, args);
  }

  qi::Future<GenericValue>
  GenericObject::xMetaCall(const std::string &retsig, const std::string &signature, const GenericFunctionParameters& args)
  {
    qi::Promise<GenericValue> out;
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      out.setError("Invalid object");
      return out.future();
    }
    const GenericFunctionParameters* newArgs = 0;
    int methodId = metaObject().methodId(signature);
#ifndef QI_REQUIRE_SIGNATURE_EXACT_MATCH
    if (methodId < 0) {

      // Try to find an other method with compatible signature
      std::vector<qi::MetaMethod> mml = metaObject().findMethod(qi::signatureSplit(signature)[1]);
      Signature sargs(signatureSplit(signature)[2]);
      for (unsigned i = 0; i < mml.size(); ++i)
      {
        Signature s(signatureSplit(mml[i].signature())[2]);
        if (sargs.isConvertibleTo(s))
        {
          qiLogVerbose("qi.object")
              << "Signature mismatch, but found compatible type "
              << mml[i].signature() <<" for " << signature;
          methodId = mml[i].uid();
          // Signature is wrapped in a tuple, unwrap
          newArgs = new GenericFunctionParameters(args.convert(s.begin().children()));
          break;
        }
      }
    }
#endif
    if (methodId < 0) {
      std::stringstream ss;
      ss << "Can't find method: " << signature << std::endl
         << "  Candidate(s):" << std::endl;
      std::vector<qi::MetaMethod>           mml = metaObject().findMethod(qi::signatureSplit(signature)[1]);
      std::vector<qi::MetaMethod>::const_iterator it;

      for (it = mml.begin(); it != mml.end(); ++it) {
        const qi::MetaMethod       &mm = *it;
        ss << "  " << mm.signature() << std::endl;
      }
      qiLogError("object") << ss.str();
      out.setError(ss.str());
      return out.future();
    }
    if (retsig != "v") {
      const qi::MetaMethod *mm = metaObject().method(methodId);
      if (!mm) {
        std::stringstream ss;
        ss << "method " << signature << "(id: " << methodId << ") disapeared mysteriously!";
        qiLogError("object") << ss.str();
        out.setError(ss.str());
        return out.future();
      }
      if (mm->sigreturn() != retsig) {
        std::stringstream ss;
        ss << "signature mismatch for return value:" << std::endl
           << "we want: " << retsig << " " << signature << std::endl
           << "we had:" << mm->sigreturn() << " " << mm->signature();
        qiLogWarning("object") << ss;
        // Let it pass, conversion system will do it's job
      }
    }
    //TODO: check for metacall to return false when not able to send the answer
    if (newArgs)
    {
      qi::Future<GenericValue> res = metaCall(methodId, *newArgs);
      delete newArgs;
      return res;
    }
    else
      return metaCall(methodId, args);
  }
  /// Resolve signature and bounce
  bool GenericObject::xMetaEmit(const std::string &signature, const GenericFunctionParameters &in) {
    if (!value || !type) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return false;
    }
       int eventId = metaObject().signalId(signature);
    if (eventId < 0)
      eventId = metaObject().methodId(signature);
    if (eventId < 0) {
      std::stringstream ss;
      ss << "Can't find event: " << signature << std::endl
         << "  Candidate(s):" << std::endl;
      std::vector<MetaSignal>           mml = metaObject().findSignal(qi::signatureSplit(signature)[1]);
      std::vector<MetaSignal>::const_iterator it;

      for (it = mml.begin(); it != mml.end(); ++it) {
        ss << "  " << it->signature() << std::endl;
      }
      qiLogError("object") << ss.str();
      return false;
    }
    metaEmit(eventId, in);
    return true;
  }

  /// Resolve signature and bounce
  qi::FutureSync<unsigned int> GenericObject::xConnect(const std::string &signature, const SignalSubscriber& functor)
  {
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return qi::makeFutureError<unsigned int>("Operating on invalid GenericObject..");
    }
    int eventId = metaObject().signalId(signature);
    if (eventId < 0) {
      std::stringstream ss;
      ss << "Can't find event: " << signature << std::endl
         << "  Candidate(s):" << std::endl;
      std::vector<MetaSignal>           mml = metaObject().findSignal(qi::signatureSplit(signature)[1]);
      std::vector<MetaSignal>::const_iterator it;

      for (it = mml.begin(); it != mml.end(); ++it) {
        ss << "  " << it->signature() << std::endl;
      }
      qiLogError("object") << ss.str();
      return qi::makeFutureError<unsigned int>(ss.str());
    }
    return connect(eventId, functor);
  }

  qi::FutureSync<unsigned int> GenericObject::connect(unsigned int event, const SignalSubscriber& sub)
  {
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return qi::makeFutureError<unsigned int>("Operating on invalid GenericObject..");
    }
    return type->connect(value, event, sub);
  }

  qi::FutureSync<void> GenericObject::disconnect(unsigned int linkId)
  {
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return qi::makeFutureError<void>("Operating on invalid GenericObject");
    }
    return type->disconnect(value, linkId);
  }

  qi::FutureSync<unsigned int> GenericObject::connect(unsigned int signal, ObjectPtr target, unsigned int slot)
  {
    return connect(signal, SignalSubscriber(target, slot));
  }

  /*
  std::vector<SignalSubscriber> GenericObject::subscribers(int eventId) const
  {
    std::vector<SignalSubscriber> res;
    if (!_p) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return res;
    }
    return _p->subscribers(eventId);
  }*/

  void GenericObject::emitEvent(const std::string& eventName,
                         qi::AutoGenericValue p1,
                         qi::AutoGenericValue p2,
                         qi::AutoGenericValue p3,
                         qi::AutoGenericValue p4,
                         qi::AutoGenericValue p5,
                         qi::AutoGenericValue p6,
                         qi::AutoGenericValue p7,
                         qi::AutoGenericValue p8)
  {
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return;
    }
    qi::AutoGenericValue* vals[8]= {&p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8};
    std::vector<qi::GenericValue> params;
    for (unsigned i=0; i<8; ++i)
      if (vals[i]->value)
        params.push_back(*vals[i]);
    // Signature construction
    std::string signature = eventName + "::(";
    for (unsigned i=0; i< params.size(); ++i)
      signature += params[i].signature();
    signature += ")";
    xMetaEmit(signature, GenericFunctionParameters(params));
  }

  int ObjectType::inherits(Type* other)
  {
    /* A registered class C can have to Type* around:
    * - TypeImpl<C*>
    * - The staticObjectType that was created by the builder.
    * So assume that any of them can be in the parentTypes list.
    */
    if (this == other)
      return 0;
    const std::vector<std::pair<Type*, int> >& parents = parentTypes();
    qiLogDebug("qi.meta") << infoString() <<" has " << parents.size() <<" parents";
    for (unsigned i=0; i<parents.size(); ++i)
    {
      if (parents[i].first->info() == other->info())
        return parents[i].second;
      ObjectType* op = dynamic_cast<ObjectType*>(parents[i].first);
      if (op)
      {
        int offset = op->inherits(other);
        if (offset != -1)
        {
          qiLogDebug("qi.meta") << "Inheritance offsets " << parents[i].second
           << " " << offset;
          return parents[i].second + offset;
        }
      }
      qiLogDebug("qi.meta") << parents[i].first->infoString() << " does not match " << other->infoString()
      <<" " << ((bool)op == (bool)dynamic_cast<ObjectType*>(other));
    }
    return -1;
  }
}

<commit_msg>Object::connect: Signature adaptation, similar to call.<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <iostream>
#include <qitype/genericobject.hpp>
#include "object_p.hpp"

namespace qi {

  GenericObject::GenericObject(ObjectType *type, void *value)
  : type(type)
  , value(value)
  {
  }

  GenericObject::~GenericObject() {
  }

  Manageable::Manageable()
  {
    _p = new ManageablePrivate();
    _p->eventLoop = getDefaultObjectEventLoop();
    _p->dying = false;
  }

  Manageable::Manageable(const Manageable& b)
  {
    _p = new ManageablePrivate();
    _p->eventLoop = b._p->eventLoop;
    _p->dying = false;
  }

  void Manageable::operator = (const Manageable& b)
  {
    this->~Manageable();
    _p = new ManageablePrivate();
    _p->eventLoop = b._p->eventLoop;
    _p->dying = false;
  }

  Manageable::~Manageable()
  {
    _p->dying = true;
    std::vector<SignalSubscriber> copy;
    {
      boost::mutex::scoped_lock sl(_p->registrationsMutex);
      copy = _p->registrations;
    }
    for (unsigned i = 0; i < copy.size(); ++i)
    {
      copy[i].source->disconnect(copy[i].linkId);
    }
    delete _p;
  }

  void Manageable::moveToEventLoop(EventLoop* el)
  {
    _p->eventLoop = el;
  }

  EventLoop* Manageable::eventLoop() const
  {
    return _p->eventLoop;
  }

  const MetaObject &GenericObject::metaObject() {
    if (!type || !value) {
      static qi::MetaObject fail;
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return fail;
    }
    return type->metaObject(value);
  }

  qi::Future<GenericValue>
  GenericObject::metaCall(unsigned int method, const GenericFunctionParameters& params, MetaCallType callType)
  {
    qi::Promise<GenericValue> out;
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      out.setError("Invalid object");
      return out.future();
    }
    try {
      return type->metaCall(value, method, params, callType);
    } catch (std::runtime_error &e) {
      out.setError(e.what());
      return out.future();
    }
  }

  void GenericObject::metaEmit(unsigned int event, const GenericFunctionParameters& args)
  {
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return;
    }
    type->metaEmit(value, event, args);
  }

  qi::Future<GenericValue>
  GenericObject::xMetaCall(const std::string &retsig, const std::string &signature, const GenericFunctionParameters& args)
  {
    qi::Promise<GenericValue> out;
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      out.setError("Invalid object");
      return out.future();
    }
    const GenericFunctionParameters* newArgs = 0;
    int methodId = metaObject().methodId(signature);
#ifndef QI_REQUIRE_SIGNATURE_EXACT_MATCH
    if (methodId < 0) {

      // Try to find an other method with compatible signature
      std::vector<qi::MetaMethod> mml = metaObject().findMethod(qi::signatureSplit(signature)[1]);
      Signature sargs(signatureSplit(signature)[2]);
      for (unsigned i = 0; i < mml.size(); ++i)
      {
        Signature s(signatureSplit(mml[i].signature())[2]);
        if (sargs.isConvertibleTo(s))
        {
          qiLogVerbose("qi.object")
              << "Signature mismatch, but found compatible type "
              << mml[i].signature() <<" for " << signature;
          methodId = mml[i].uid();
          // Signature is wrapped in a tuple, unwrap
          newArgs = new GenericFunctionParameters(args.convert(s.begin().children()));
          break;
        }
      }
    }
#endif
    if (methodId < 0) {
      std::stringstream ss;
      ss << "Can't find method: " << signature << std::endl
         << "  Candidate(s):" << std::endl;
      std::vector<qi::MetaMethod>           mml = metaObject().findMethod(qi::signatureSplit(signature)[1]);
      std::vector<qi::MetaMethod>::const_iterator it;

      for (it = mml.begin(); it != mml.end(); ++it) {
        const qi::MetaMethod       &mm = *it;
        ss << "  " << mm.signature() << std::endl;
      }
      qiLogError("object") << ss.str();
      out.setError(ss.str());
      return out.future();
    }
    if (retsig != "v") {
      const qi::MetaMethod *mm = metaObject().method(methodId);
      if (!mm) {
        std::stringstream ss;
        ss << "method " << signature << "(id: " << methodId << ") disapeared mysteriously!";
        qiLogError("object") << ss.str();
        out.setError(ss.str());
        return out.future();
      }
      if (mm->sigreturn() != retsig) {
        std::stringstream ss;
        ss << "signature mismatch for return value:" << std::endl
           << "we want: " << retsig << " " << signature << std::endl
           << "we had:" << mm->sigreturn() << " " << mm->signature();
        qiLogWarning("object") << ss;
        // Let it pass, conversion system will do it's job
      }
    }
    //TODO: check for metacall to return false when not able to send the answer
    if (newArgs)
    {
      qi::Future<GenericValue> res = metaCall(methodId, *newArgs);
      delete newArgs;
      return res;
    }
    else
      return metaCall(methodId, args);
  }
  /// Resolve signature and bounce
  bool GenericObject::xMetaEmit(const std::string &signature, const GenericFunctionParameters &in) {
    if (!value || !type) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return false;
    }
       int eventId = metaObject().signalId(signature);
    if (eventId < 0)
      eventId = metaObject().methodId(signature);
    if (eventId < 0) {
      std::stringstream ss;
      ss << "Can't find event: " << signature << std::endl
         << "  Candidate(s):" << std::endl;
      std::vector<MetaSignal>           mml = metaObject().findSignal(qi::signatureSplit(signature)[1]);
      std::vector<MetaSignal>::const_iterator it;

      for (it = mml.begin(); it != mml.end(); ++it) {
        ss << "  " << it->signature() << std::endl;
      }
      qiLogError("object") << ss.str();
      return false;
    }
    metaEmit(eventId, in);
    return true;
  }

  /// Resolve signature and bounce
  qi::FutureSync<unsigned int> GenericObject::xConnect(const std::string &signature, const SignalSubscriber& functor)
  {
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return qi::makeFutureError<unsigned int>("Operating on invalid GenericObject..");
    }
    int eventId = metaObject().signalId(signature);

  #ifndef QI_REQUIRE_SIGNATURE_EXACT_MATCH
    if (eventId < 0) {
      // Try to find an other event with compatible signature
      std::vector<qi::MetaSignal> mml = metaObject().findSignal(qi::signatureSplit(signature)[1]);
      Signature sargs(signatureSplit(signature)[2]);
      for (unsigned i = 0; i < mml.size(); ++i)
      {
        Signature s(signatureSplit(mml[i].signature())[2]);
        qiLogDebug("qi.object") << "Checking compatibility " << s.toString() << ' '
         << sargs.toString();
         // Order is reversed from method call check.
        if (s.isConvertibleTo(sargs))
        {
          qiLogVerbose("qi.object")
              << "Signature mismatch, but found compatible type "
              << mml[i].signature() <<" for " << signature;
          eventId = mml[i].uid();
          break;
        }
      }
    }
#endif
    if (eventId < 0) {
      std::stringstream ss;
      ss << "Can't find event: " << signature << std::endl
         << "  Candidate(s):" << std::endl;
      std::vector<MetaSignal>           mml = metaObject().findSignal(qi::signatureSplit(signature)[1]);
      std::vector<MetaSignal>::const_iterator it;

      for (it = mml.begin(); it != mml.end(); ++it) {
        ss << "  " << it->signature() << std::endl;
      }
      qiLogError("object") << ss.str();
      return qi::makeFutureError<unsigned int>(ss.str());
    }
    return connect(eventId, functor);
  }

  qi::FutureSync<unsigned int> GenericObject::connect(unsigned int event, const SignalSubscriber& sub)
  {
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return qi::makeFutureError<unsigned int>("Operating on invalid GenericObject..");
    }
    return type->connect(value, event, sub);
  }

  qi::FutureSync<void> GenericObject::disconnect(unsigned int linkId)
  {
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return qi::makeFutureError<void>("Operating on invalid GenericObject");
    }
    return type->disconnect(value, linkId);
  }

  qi::FutureSync<unsigned int> GenericObject::connect(unsigned int signal, ObjectPtr target, unsigned int slot)
  {
    return connect(signal, SignalSubscriber(target, slot));
  }

  /*
  std::vector<SignalSubscriber> GenericObject::subscribers(int eventId) const
  {
    std::vector<SignalSubscriber> res;
    if (!_p) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return res;
    }
    return _p->subscribers(eventId);
  }*/

  void GenericObject::emitEvent(const std::string& eventName,
                         qi::AutoGenericValue p1,
                         qi::AutoGenericValue p2,
                         qi::AutoGenericValue p3,
                         qi::AutoGenericValue p4,
                         qi::AutoGenericValue p5,
                         qi::AutoGenericValue p6,
                         qi::AutoGenericValue p7,
                         qi::AutoGenericValue p8)
  {
    if (!type || !value) {
      qiLogWarning("qi.object") << "Operating on invalid GenericObject..";
      return;
    }
    qi::AutoGenericValue* vals[8]= {&p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8};
    std::vector<qi::GenericValue> params;
    for (unsigned i=0; i<8; ++i)
      if (vals[i]->value)
        params.push_back(*vals[i]);
    // Signature construction
    std::string signature = eventName + "::(";
    for (unsigned i=0; i< params.size(); ++i)
      signature += params[i].signature();
    signature += ")";
    xMetaEmit(signature, GenericFunctionParameters(params));
  }

  int ObjectType::inherits(Type* other)
  {
    /* A registered class C can have to Type* around:
    * - TypeImpl<C*>
    * - The staticObjectType that was created by the builder.
    * So assume that any of them can be in the parentTypes list.
    */
    if (this == other)
      return 0;
    const std::vector<std::pair<Type*, int> >& parents = parentTypes();
    qiLogDebug("qi.meta") << infoString() <<" has " << parents.size() <<" parents";
    for (unsigned i=0; i<parents.size(); ++i)
    {
      if (parents[i].first->info() == other->info())
        return parents[i].second;
      ObjectType* op = dynamic_cast<ObjectType*>(parents[i].first);
      if (op)
      {
        int offset = op->inherits(other);
        if (offset != -1)
        {
          qiLogDebug("qi.meta") << "Inheritance offsets " << parents[i].second
           << " " << offset;
          return parents[i].second + offset;
        }
      }
      qiLogDebug("qi.meta") << parents[i].first->infoString() << " does not match " << other->infoString()
      <<" " << ((bool)op == (bool)dynamic_cast<ObjectType*>(other));
    }
    return -1;
  }
}

<|endoftext|>


<commit_before>// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/vulkan/vulkan_device.h"

#include <limits>
#include <map>
#include <vector>

#include "flutter/vulkan/vulkan_proc_table.h"
#include "flutter/vulkan/vulkan_surface.h"
#include "flutter/vulkan/vulkan_utilities.h"
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
#include "third_party/skia/src/gpu/vk/GrVkUtil.h"

namespace vulkan {

constexpr auto kVulkanInvalidGraphicsQueueIndex =
    std::numeric_limits<uint32_t>::max();

static uint32_t FindGraphicsQueueIndex(
    const std::vector<VkQueueFamilyProperties>& properties) {
  for (uint32_t i = 0, count = static_cast<uint32_t>(properties.size());
       i < count; i++) {
    if (properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
      return i;
    }
  }
  return kVulkanInvalidGraphicsQueueIndex;
}

VulkanDevice::VulkanDevice(VulkanProcTable& p_vk,
                           VulkanHandle<VkPhysicalDevice> physical_device)
    : vk(p_vk),
      physical_device_(std::move(physical_device)),
      graphics_queue_index_(std::numeric_limits<uint32_t>::max()),
      valid_(false) {
  if (!physical_device_ || !vk.AreInstanceProcsSetup()) {
    return;
  }

  graphics_queue_index_ = FindGraphicsQueueIndex(GetQueueFamilyProperties());

  if (graphics_queue_index_ == kVulkanInvalidGraphicsQueueIndex) {
    FXL_DLOG(INFO) << "Could not find the graphics queue index.";
    return;
  }

  const float priorities[1] = {1.0f};

  const VkDeviceQueueCreateInfo queue_create = {
      .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
      .pNext = nullptr,
      .flags = 0,
      .queueFamilyIndex = graphics_queue_index_,
      .queueCount = 1,
      .pQueuePriorities = priorities,
  };

  const char* extensions[] = {
    VK_KHR_SWAPCHAIN_EXTENSION_NAME,
#if OS_FUCHSIA
    VK_GOOGLE_EXTERNAL_MEMORY_MAGMA_EXTENSION_NAME,
    VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
    VK_KHR_EXTERNAL_SEMAPHORE_FUCHSIA_EXTENSION_NAME,
#endif
  };

  auto enabled_layers = DeviceLayersToEnable(vk, physical_device_);

  const char* layers[enabled_layers.size()];

  for (size_t i = 0; i < enabled_layers.size(); i++) {
    layers[i] = enabled_layers[i].c_str();
  }

  const VkDeviceCreateInfo create_info = {
      .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
      .pNext = nullptr,
      .flags = 0,
      .queueCreateInfoCount = 1,
      .pQueueCreateInfos = &queue_create,
      .enabledLayerCount = static_cast<uint32_t>(enabled_layers.size()),
      .ppEnabledLayerNames = layers,
      .enabledExtensionCount = sizeof(extensions) / sizeof(const char*),
      .ppEnabledExtensionNames = extensions,
      .pEnabledFeatures = nullptr,
  };

  VkDevice device = VK_NULL_HANDLE;

  if (VK_CALL_LOG_ERROR(vk.CreateDevice(physical_device_, &create_info, nullptr,
                                        &device)) != VK_SUCCESS) {
    FXL_DLOG(INFO) << "Could not create device.";
    return;
  }

  device_ = {device,
             [this](VkDevice device) { vk.DestroyDevice(device, nullptr); }};

  if (!vk.SetupDeviceProcAddresses(device_)) {
    FXL_DLOG(INFO) << "Could not setup device proc addresses.";
    return;
  }

  VkQueue queue = VK_NULL_HANDLE;

  vk.GetDeviceQueue(device_, graphics_queue_index_, 0, &queue);

  if (queue == VK_NULL_HANDLE) {
    FXL_DLOG(INFO) << "Could not get the device queue handle.";
    return;
  }

  queue_ = queue;

  const VkCommandPoolCreateInfo command_pool_create_info = {
      .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
      .pNext = nullptr,
      .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
      .queueFamilyIndex = 0,
  };

  VkCommandPool command_pool = VK_NULL_HANDLE;
  if (VK_CALL_LOG_ERROR(vk.CreateCommandPool(device_, &command_pool_create_info,
                                             nullptr, &command_pool)) !=
      VK_SUCCESS) {
    FXL_DLOG(INFO) << "Could not create the command pool.";
    return;
  }

  command_pool_ = {command_pool, [this](VkCommandPool pool) {
                     vk.DestroyCommandPool(device_, pool, nullptr);
                   }};

  valid_ = true;
}

VulkanDevice::~VulkanDevice() {
  FXL_ALLOW_UNUSED_LOCAL(WaitIdle());
}

bool VulkanDevice::IsValid() const {
  return valid_;
}

bool VulkanDevice::WaitIdle() const {
  return VK_CALL_LOG_ERROR(vk.DeviceWaitIdle(device_)) == VK_SUCCESS;
}

const VulkanHandle<VkDevice>& VulkanDevice::GetHandle() const {
  return device_;
}

void VulkanDevice::ReleaseDeviceOwnership() {
  device_.ReleaseOwnership();
}

const VulkanHandle<VkPhysicalDevice>& VulkanDevice::GetPhysicalDeviceHandle()
    const {
  return physical_device_;
}

const VulkanHandle<VkQueue>& VulkanDevice::GetQueueHandle() const {
  return queue_;
}

const VulkanHandle<VkCommandPool>& VulkanDevice::GetCommandPool() const {
  return command_pool_;
}

uint32_t VulkanDevice::GetGraphicsQueueIndex() const {
  return graphics_queue_index_;
}

bool VulkanDevice::GetSurfaceCapabilities(
    const VulkanSurface& surface,
    VkSurfaceCapabilitiesKHR* capabilities) const {
  if (!surface.IsValid() || capabilities == nullptr) {
    return false;
  }

  bool success =
      VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceCapabilitiesKHR(
          physical_device_, surface.Handle(), capabilities)) == VK_SUCCESS;

  if (!success) {
    return false;
  }

  // Check if the physical device surface capabilities are valid. If so, there
  // is nothing more to do.
  if (capabilities->currentExtent.width != 0xFFFFFFFF &&
      capabilities->currentExtent.height != 0xFFFFFFFF) {
    return true;
  }

  // Ask the native surface for its size as a fallback.
  SkISize size = surface.GetSize();

  if (size.width() == 0 || size.height() == 0) {
    return false;
  }

  capabilities->currentExtent.width = size.width();
  capabilities->currentExtent.height = size.height();
  return true;
}

bool VulkanDevice::GetPhysicalDeviceFeatures(
    VkPhysicalDeviceFeatures* features) const {
  if (features == nullptr || !physical_device_) {
    return false;
  }
  vk.GetPhysicalDeviceFeatures(physical_device_, features);
  return true;
}

bool VulkanDevice::GetPhysicalDeviceFeaturesSkia(uint32_t* sk_features) const {
  if (sk_features == nullptr) {
    return false;
  }

  VkPhysicalDeviceFeatures features;

  if (!GetPhysicalDeviceFeatures(&features)) {
    return false;
  }

  uint32_t flags = 0;

  if (features.geometryShader) {
    flags |= kGeometryShader_GrVkFeatureFlag;
  }
  if (features.dualSrcBlend) {
    flags |= kDualSrcBlend_GrVkFeatureFlag;
  }
  if (features.sampleRateShading) {
    flags |= kSampleRateShading_GrVkFeatureFlag;
  }

  *sk_features = flags;
  return true;
}

std::vector<VkQueueFamilyProperties> VulkanDevice::GetQueueFamilyProperties()
    const {
  uint32_t count = 0;

  vk.GetPhysicalDeviceQueueFamilyProperties(physical_device_, &count, nullptr);

  std::vector<VkQueueFamilyProperties> properties;
  properties.resize(count, {});

  vk.GetPhysicalDeviceQueueFamilyProperties(physical_device_, &count,
                                            properties.data());

  return properties;
}

bool VulkanDevice::ChooseSurfaceFormat(const VulkanSurface& surface,
                                       VkSurfaceFormatKHR* format) const {
  if (!surface.IsValid() || format == nullptr) {
    return false;
  }

  uint32_t format_count = 0;
  if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceFormatsKHR(
          physical_device_, surface.Handle(), &format_count, nullptr)) !=
      VK_SUCCESS) {
    return false;
  }

  if (format_count == 0) {
    return false;
  }

  VkSurfaceFormatKHR formats[format_count];
  if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceFormatsKHR(
          physical_device_, surface.Handle(), &format_count, formats)) !=
      VK_SUCCESS) {
    return false;
  }

  std::map<VkFormat, VkSurfaceFormatKHR> supported_formats;

  for (uint32_t i = 0; i < format_count; i++) {
    GrPixelConfig pixel_config = GrVkFormatToPixelConfig(formats[i].format);
    if (pixel_config != kUnknown_GrPixelConfig) {
      supported_formats[formats[i].format] = formats[i];
    }
  }

  if (supported_formats.size() == 0) {
    return false;
  }

  const std::vector<VkFormat> desired_formats = {
      VK_FORMAT_R8G8B8A8_SRGB,        // kSRGBA_8888_GrPixelConfig
      VK_FORMAT_B8G8R8A8_SRGB,        // kSBGRA_8888_GrPixelConfig
      VK_FORMAT_R16G16B16A16_SFLOAT,  // kRGBA_half_GrPixelConfig
      VK_FORMAT_R8G8B8A8_UNORM,       // kRGBA_8888_GrPixelConfig
      VK_FORMAT_B8G8R8A8_UNORM,       // kBGRA_8888_GrPixelConfig
  };

  // Try to find the first supported format in the list of desired formats.
  for (VkFormat current_format : desired_formats) {
    auto found = supported_formats.find(current_format);
    if (found != supported_formats.end()) {
      *format = found->second;
      return true;
    }
  }

  // None of the desired formats were supported. Return the first supported
  // format even if we don't like it all that much (it has already returned true
  // for GrVkFormatToPixelConfig).
  *format = supported_formats.begin()->second;
  return true;
}

bool VulkanDevice::ChoosePresentMode(const VulkanSurface& surface,
                                     VkPresentModeKHR* present_mode) const {
  if (!surface.IsValid() || present_mode == nullptr) {
    return false;
  }

  // https://github.com/LunarG/VulkanSamples/issues/98 indicates that
  // VK_PRESENT_MODE_FIFO_KHR is preferable on mobile platforms. The problems
  // mentioned in the ticket w.r.t the application being faster that the refresh
  // rate of the screen should not be faced by any Flutter platforms as they are
  // powered by Vsync pulses instead of depending the the submit to block.
  // However, for platforms that don't have VSync providers setup, it is better
  // to fall back to FIFO. For platforms that do have VSync providers, there
  // should be little difference. In case there is a need for a mode other than
  // FIFO, availability checks must be performed here before returning the
  // result. FIFO is always present.
  *present_mode = VK_PRESENT_MODE_FIFO_KHR;
  return true;
}

bool VulkanDevice::QueueSubmit(
    std::vector<VkPipelineStageFlags> wait_dest_pipeline_stages,
    const std::vector<VkSemaphore>& wait_semaphores,
    const std::vector<VkSemaphore>& signal_semaphores,
    const std::vector<VkCommandBuffer>& command_buffers,
    const VulkanHandle<VkFence>& fence) const {
  if (wait_semaphores.size() != wait_dest_pipeline_stages.size()) {
    return false;
  }

  const VkSubmitInfo submit_info = {
      .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
      .pNext = nullptr,
      .waitSemaphoreCount = static_cast<uint32_t>(wait_semaphores.size()),
      .pWaitSemaphores = wait_semaphores.data(),
      .pWaitDstStageMask = wait_dest_pipeline_stages.data(),
      .commandBufferCount = static_cast<uint32_t>(command_buffers.size()),
      .pCommandBuffers = command_buffers.data(),
      .signalSemaphoreCount = static_cast<uint32_t>(signal_semaphores.size()),
      .pSignalSemaphores = signal_semaphores.data(),
  };

  if (VK_CALL_LOG_ERROR(vk.QueueSubmit(queue_, 1, &submit_info, fence)) !=
      VK_SUCCESS) {
    return false;
  }

  return true;
}

}  // namespace vulkan
<commit_msg>Don't query for deprecated magma extension (#4292)<commit_after>// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/vulkan/vulkan_device.h"

#include <limits>
#include <map>
#include <vector>

#include "flutter/vulkan/vulkan_proc_table.h"
#include "flutter/vulkan/vulkan_surface.h"
#include "flutter/vulkan/vulkan_utilities.h"
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
#include "third_party/skia/src/gpu/vk/GrVkUtil.h"

namespace vulkan {

constexpr auto kVulkanInvalidGraphicsQueueIndex =
    std::numeric_limits<uint32_t>::max();

static uint32_t FindGraphicsQueueIndex(
    const std::vector<VkQueueFamilyProperties>& properties) {
  for (uint32_t i = 0, count = static_cast<uint32_t>(properties.size());
       i < count; i++) {
    if (properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
      return i;
    }
  }
  return kVulkanInvalidGraphicsQueueIndex;
}

VulkanDevice::VulkanDevice(VulkanProcTable& p_vk,
                           VulkanHandle<VkPhysicalDevice> physical_device)
    : vk(p_vk),
      physical_device_(std::move(physical_device)),
      graphics_queue_index_(std::numeric_limits<uint32_t>::max()),
      valid_(false) {
  if (!physical_device_ || !vk.AreInstanceProcsSetup()) {
    return;
  }

  graphics_queue_index_ = FindGraphicsQueueIndex(GetQueueFamilyProperties());

  if (graphics_queue_index_ == kVulkanInvalidGraphicsQueueIndex) {
    FXL_DLOG(INFO) << "Could not find the graphics queue index.";
    return;
  }

  const float priorities[1] = {1.0f};

  const VkDeviceQueueCreateInfo queue_create = {
      .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
      .pNext = nullptr,
      .flags = 0,
      .queueFamilyIndex = graphics_queue_index_,
      .queueCount = 1,
      .pQueuePriorities = priorities,
  };

  const char* extensions[] = {
    VK_KHR_SWAPCHAIN_EXTENSION_NAME,
#if OS_FUCHSIA
    VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
    VK_KHR_EXTERNAL_SEMAPHORE_FUCHSIA_EXTENSION_NAME,
#endif
  };

  auto enabled_layers = DeviceLayersToEnable(vk, physical_device_);

  const char* layers[enabled_layers.size()];

  for (size_t i = 0; i < enabled_layers.size(); i++) {
    layers[i] = enabled_layers[i].c_str();
  }

  const VkDeviceCreateInfo create_info = {
      .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
      .pNext = nullptr,
      .flags = 0,
      .queueCreateInfoCount = 1,
      .pQueueCreateInfos = &queue_create,
      .enabledLayerCount = static_cast<uint32_t>(enabled_layers.size()),
      .ppEnabledLayerNames = layers,
      .enabledExtensionCount = sizeof(extensions) / sizeof(const char*),
      .ppEnabledExtensionNames = extensions,
      .pEnabledFeatures = nullptr,
  };

  VkDevice device = VK_NULL_HANDLE;

  if (VK_CALL_LOG_ERROR(vk.CreateDevice(physical_device_, &create_info, nullptr,
                                        &device)) != VK_SUCCESS) {
    FXL_DLOG(INFO) << "Could not create device.";
    return;
  }

  device_ = {device,
             [this](VkDevice device) { vk.DestroyDevice(device, nullptr); }};

  if (!vk.SetupDeviceProcAddresses(device_)) {
    FXL_DLOG(INFO) << "Could not setup device proc addresses.";
    return;
  }

  VkQueue queue = VK_NULL_HANDLE;

  vk.GetDeviceQueue(device_, graphics_queue_index_, 0, &queue);

  if (queue == VK_NULL_HANDLE) {
    FXL_DLOG(INFO) << "Could not get the device queue handle.";
    return;
  }

  queue_ = queue;

  const VkCommandPoolCreateInfo command_pool_create_info = {
      .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
      .pNext = nullptr,
      .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
      .queueFamilyIndex = 0,
  };

  VkCommandPool command_pool = VK_NULL_HANDLE;
  if (VK_CALL_LOG_ERROR(vk.CreateCommandPool(device_, &command_pool_create_info,
                                             nullptr, &command_pool)) !=
      VK_SUCCESS) {
    FXL_DLOG(INFO) << "Could not create the command pool.";
    return;
  }

  command_pool_ = {command_pool, [this](VkCommandPool pool) {
                     vk.DestroyCommandPool(device_, pool, nullptr);
                   }};

  valid_ = true;
}

VulkanDevice::~VulkanDevice() {
  FXL_ALLOW_UNUSED_LOCAL(WaitIdle());
}

bool VulkanDevice::IsValid() const {
  return valid_;
}

bool VulkanDevice::WaitIdle() const {
  return VK_CALL_LOG_ERROR(vk.DeviceWaitIdle(device_)) == VK_SUCCESS;
}

const VulkanHandle<VkDevice>& VulkanDevice::GetHandle() const {
  return device_;
}

void VulkanDevice::ReleaseDeviceOwnership() {
  device_.ReleaseOwnership();
}

const VulkanHandle<VkPhysicalDevice>& VulkanDevice::GetPhysicalDeviceHandle()
    const {
  return physical_device_;
}

const VulkanHandle<VkQueue>& VulkanDevice::GetQueueHandle() const {
  return queue_;
}

const VulkanHandle<VkCommandPool>& VulkanDevice::GetCommandPool() const {
  return command_pool_;
}

uint32_t VulkanDevice::GetGraphicsQueueIndex() const {
  return graphics_queue_index_;
}

bool VulkanDevice::GetSurfaceCapabilities(
    const VulkanSurface& surface,
    VkSurfaceCapabilitiesKHR* capabilities) const {
  if (!surface.IsValid() || capabilities == nullptr) {
    return false;
  }

  bool success =
      VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceCapabilitiesKHR(
          physical_device_, surface.Handle(), capabilities)) == VK_SUCCESS;

  if (!success) {
    return false;
  }

  // Check if the physical device surface capabilities are valid. If so, there
  // is nothing more to do.
  if (capabilities->currentExtent.width != 0xFFFFFFFF &&
      capabilities->currentExtent.height != 0xFFFFFFFF) {
    return true;
  }

  // Ask the native surface for its size as a fallback.
  SkISize size = surface.GetSize();

  if (size.width() == 0 || size.height() == 0) {
    return false;
  }

  capabilities->currentExtent.width = size.width();
  capabilities->currentExtent.height = size.height();
  return true;
}

bool VulkanDevice::GetPhysicalDeviceFeatures(
    VkPhysicalDeviceFeatures* features) const {
  if (features == nullptr || !physical_device_) {
    return false;
  }
  vk.GetPhysicalDeviceFeatures(physical_device_, features);
  return true;
}

bool VulkanDevice::GetPhysicalDeviceFeaturesSkia(uint32_t* sk_features) const {
  if (sk_features == nullptr) {
    return false;
  }

  VkPhysicalDeviceFeatures features;

  if (!GetPhysicalDeviceFeatures(&features)) {
    return false;
  }

  uint32_t flags = 0;

  if (features.geometryShader) {
    flags |= kGeometryShader_GrVkFeatureFlag;
  }
  if (features.dualSrcBlend) {
    flags |= kDualSrcBlend_GrVkFeatureFlag;
  }
  if (features.sampleRateShading) {
    flags |= kSampleRateShading_GrVkFeatureFlag;
  }

  *sk_features = flags;
  return true;
}

std::vector<VkQueueFamilyProperties> VulkanDevice::GetQueueFamilyProperties()
    const {
  uint32_t count = 0;

  vk.GetPhysicalDeviceQueueFamilyProperties(physical_device_, &count, nullptr);

  std::vector<VkQueueFamilyProperties> properties;
  properties.resize(count, {});

  vk.GetPhysicalDeviceQueueFamilyProperties(physical_device_, &count,
                                            properties.data());

  return properties;
}

bool VulkanDevice::ChooseSurfaceFormat(const VulkanSurface& surface,
                                       VkSurfaceFormatKHR* format) const {
  if (!surface.IsValid() || format == nullptr) {
    return false;
  }

  uint32_t format_count = 0;
  if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceFormatsKHR(
          physical_device_, surface.Handle(), &format_count, nullptr)) !=
      VK_SUCCESS) {
    return false;
  }

  if (format_count == 0) {
    return false;
  }

  VkSurfaceFormatKHR formats[format_count];
  if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceFormatsKHR(
          physical_device_, surface.Handle(), &format_count, formats)) !=
      VK_SUCCESS) {
    return false;
  }

  std::map<VkFormat, VkSurfaceFormatKHR> supported_formats;

  for (uint32_t i = 0; i < format_count; i++) {
    GrPixelConfig pixel_config = GrVkFormatToPixelConfig(formats[i].format);
    if (pixel_config != kUnknown_GrPixelConfig) {
      supported_formats[formats[i].format] = formats[i];
    }
  }

  if (supported_formats.size() == 0) {
    return false;
  }

  const std::vector<VkFormat> desired_formats = {
      VK_FORMAT_R8G8B8A8_SRGB,        // kSRGBA_8888_GrPixelConfig
      VK_FORMAT_B8G8R8A8_SRGB,        // kSBGRA_8888_GrPixelConfig
      VK_FORMAT_R16G16B16A16_SFLOAT,  // kRGBA_half_GrPixelConfig
      VK_FORMAT_R8G8B8A8_UNORM,       // kRGBA_8888_GrPixelConfig
      VK_FORMAT_B8G8R8A8_UNORM,       // kBGRA_8888_GrPixelConfig
  };

  // Try to find the first supported format in the list of desired formats.
  for (VkFormat current_format : desired_formats) {
    auto found = supported_formats.find(current_format);
    if (found != supported_formats.end()) {
      *format = found->second;
      return true;
    }
  }

  // None of the desired formats were supported. Return the first supported
  // format even if we don't like it all that much (it has already returned true
  // for GrVkFormatToPixelConfig).
  *format = supported_formats.begin()->second;
  return true;
}

bool VulkanDevice::ChoosePresentMode(const VulkanSurface& surface,
                                     VkPresentModeKHR* present_mode) const {
  if (!surface.IsValid() || present_mode == nullptr) {
    return false;
  }

  // https://github.com/LunarG/VulkanSamples/issues/98 indicates that
  // VK_PRESENT_MODE_FIFO_KHR is preferable on mobile platforms. The problems
  // mentioned in the ticket w.r.t the application being faster that the refresh
  // rate of the screen should not be faced by any Flutter platforms as they are
  // powered by Vsync pulses instead of depending the the submit to block.
  // However, for platforms that don't have VSync providers setup, it is better
  // to fall back to FIFO. For platforms that do have VSync providers, there
  // should be little difference. In case there is a need for a mode other than
  // FIFO, availability checks must be performed here before returning the
  // result. FIFO is always present.
  *present_mode = VK_PRESENT_MODE_FIFO_KHR;
  return true;
}

bool VulkanDevice::QueueSubmit(
    std::vector<VkPipelineStageFlags> wait_dest_pipeline_stages,
    const std::vector<VkSemaphore>& wait_semaphores,
    const std::vector<VkSemaphore>& signal_semaphores,
    const std::vector<VkCommandBuffer>& command_buffers,
    const VulkanHandle<VkFence>& fence) const {
  if (wait_semaphores.size() != wait_dest_pipeline_stages.size()) {
    return false;
  }

  const VkSubmitInfo submit_info = {
      .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
      .pNext = nullptr,
      .waitSemaphoreCount = static_cast<uint32_t>(wait_semaphores.size()),
      .pWaitSemaphores = wait_semaphores.data(),
      .pWaitDstStageMask = wait_dest_pipeline_stages.data(),
      .commandBufferCount = static_cast<uint32_t>(command_buffers.size()),
      .pCommandBuffers = command_buffers.data(),
      .signalSemaphoreCount = static_cast<uint32_t>(signal_semaphores.size()),
      .pSignalSemaphores = signal_semaphores.data(),
  };

  if (VK_CALL_LOG_ERROR(vk.QueueSubmit(queue_, 1, &submit_info, fence)) !=
      VK_SUCCESS) {
    return false;
  }

  return true;
}

}  // namespace vulkan
<|endoftext|>


<commit_before>// This file is part of the dune-pymor project:
//   https://github.com/pyMor/dune-pymor
// Copyright Holders: Felix Albrecht, Stephan Rave
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_PYMOR_LA_CONTAINER_EIGEN_HH
#define DUNE_PYMOR_LA_CONTAINER_EIGEN_HH

#if HAVE_EIGEN

#include <dune/stuff/la/container/eigen.hh>

#include "interfaces.hh"

namespace Dune {
namespace Pymor {
namespace LA {

class EigenDenseVector
  : public Dune::Stuff::LA::EigenDenseVector< double >
  , public Dune::Pymor::LA::VectorInterface
{
  typedef Dune::Stuff::LA::EigenDenseVector< double > BaseType;
public:
  typedef EigenDenseVector ThisType;

  EigenDenseVector(const int ss)
    : BaseType(ss)
  {}

  static ThisType* create(const int ss)
  {
    return new ThisType(ss);
  }

  virtual std::string type() const
  {
    return "dunepymor.vector.eigendense";
  }

  virtual int dim() const
  {
    return BaseType::size();
  }
}; // class EigenDenseVector

} // namespace LA
} // namespace Pymor
} // namespace Dune

#endif // HAVE_EIGEN

#endif // DUNE_PYMOR_LA_CONTAINER_EIGEN_HH
<commit_msg>[la.container.eigen] added EigenDenseVector<commit_after>// This file is part of the dune-pymor project:
//   https://github.com/pyMor/dune-pymor
// Copyright Holders: Felix Albrecht, Stephan Rave
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_PYMOR_LA_CONTAINER_EIGEN_HH
#define DUNE_PYMOR_LA_CONTAINER_EIGEN_HH

//#if HAVE_EIGEN

#include <dune/stuff/common/float_cmp.hh>
#include <dune/stuff/la/container/eigen.hh>

#include "interfaces.hh"

namespace Dune {
namespace Pymor {
namespace LA {

class EigenDenseVector
  : public Dune::Stuff::LA::EigenDenseVector< double >
{
  typedef Dune::Stuff::LA::EigenDenseVector< double > BaseType;
public:
  typedef EigenDenseVector                            ThisType;

  EigenDenseVector(const int ss)
    : BaseType(ss)
  {}

  EigenDenseVector(const BaseType& other)
    : BaseType(other)
  {}

  static ThisType* create(const int ss)
  {
    return new ThisType(ss);
  }

  virtual std::string type() const
  {
    return "dunepymor.vector.eigendense";
  }

  virtual int dim() const
  {
    return BaseType::size();
  }

  bool almost_equal(const ThisType* other,
                    const double epsilon = Dune::FloatCmp::DefaultEpsilon< double >::value()) const
  {
    assert(dim() == other->dim() && "Sizes do not match!");
    return Dune::Stuff::Common::FloatCmp::eq(*this, *other, epsilon);
  } // ... almost_equal(...)

  void scal(const double alpha)
  {
    BaseType::backend() *= alpha;
  }

  void axpy(const double alpha, const ThisType* x)
  {
    assert(dim() == x->dim() && "Sizes do not match!");
    BaseType::backend() += x->backend() * alpha;
  } // ... axpy(...)

  double dot(const ThisType* other) const
  {
    assert(dim() == other->dim() && "Sizes do not match!");
    return BaseType::backend().transpose() * other->backend();
  } // ... dot(...)

  double l1_norm() const
  {
    return BaseType::backend().lpNorm< 1 >();
  }

  double l2_norm() const
  {
    return BaseType::backend().norm();
  }

  double sup_norm() const
  {
    return BaseType::backend().lpNorm< ::Eigen::Infinity >();
  }

  std::vector< double > components(const std::vector< int >& component_indices) const
  {
    assert(int(component_indices.size()) <= dim() && "Sizes do not match!");
    std::vector< double > values(component_indices.size(), 0);
    for (size_t ii = 0; ii < component_indices.size(); ++ii) {
      const int component = component_indices[ii];
      assert(0 <= component && "Wrong component index given!");
      assert(component < dim() && "Wrong component index given!");
      values[ii] = BaseType::backend()[component];
    }
    return values;
  } // ... components(...)

  std::vector< double > amax() const
  {
    std::vector< double > result(2, 0.0);
    size_t minIndex = 0;
    size_t maxIndex = 0;
    const double minimum = BaseType::backend().minCoeff(&minIndex);
    const double maximum = BaseType::backend().maxCoeff(&maxIndex);
    if (std::abs(maximum) >= std::abs(minimum)) {
      result[0] = minIndex;
      result[1] = std::abs(minimum);
    } else {
      result[0] = maxIndex;
      result[1] = maximum;
    }
    return result;
  } // ... amax(...)

  ThisType* add(const ThisType* other) const
  {
    assert(dim() == other->dim() && "Sizes do not match!");
    ThisType* result = new ThisType(*this);
    result->backend() += other->backend();
    return result;
  } // ... add(...)

  void iadd(const ThisType* other)
  {
    assert(dim() == other->dim() && "Sizes do not match!");
    BaseType::backend() += other->backend();
  } // ... iadd(...)

  ThisType* sub(const ThisType* other) const
  {
    assert(dim() == other->dim() && "Sizes do not match!");
    ThisType* result = new ThisType(*this);
    result->backend() -= other->backend();
    return result;
  } // ... sub(...)

  void isub(const ThisType* other)
  {
    assert(dim() == other->dim() && "Sizes do not match!");
    BaseType::backend() -= other->backend();
  } // ... isub(...)
}; // class EigenDenseVector

} // namespace LA
} // namespace Pymor
} // namespace Dune

//#endif // HAVE_EIGEN

#endif // DUNE_PYMOR_LA_CONTAINER_EIGEN_HH
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <vcl/svapp.hxx>
#include <vcl/graph.hxx>
#include <vcl/bmpacc.hxx>
#include <vcl/msgbox.hxx>
#include <svl/solar.hrc>
#include <vcl/fltcall.hxx>
#include <vcl/FilterConfigItem.hxx>

//============================ PBMWriter ==================================

class PBMWriter {

private:

    SvStream&           m_rOStm;            // the output PBM file
    sal_uInt16          mpOStmOldModus;

    sal_Bool            mbStatus;
    sal_Int32           mnMode;             // 0 -> raw, 1-> ascii
    BitmapReadAccess*   mpAcc;
    sal_uLong           mnWidth, mnHeight;  // size in pixel

    sal_Bool            ImplWriteHeader();
    void                ImplWriteBody();
    void                ImplWriteNumber( sal_Int32 );

    com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > xStatusIndicator;

public:
    PBMWriter(SvStream &rPBM);
    ~PBMWriter();

    sal_Bool WritePBM( const Graphic& rGraphic, FilterConfigItem* pFilterConfigItem );
};

//=================== Methods of PBMWriter ==============================

PBMWriter::PBMWriter(SvStream &rPBM)
    : m_rOStm(rPBM)
    , mbStatus(sal_True)
    , mpAcc(NULL)
{
}

PBMWriter::~PBMWriter()
{
}

sal_Bool PBMWriter::WritePBM( const Graphic& rGraphic, FilterConfigItem* pFilterConfigItem )
{
    if ( pFilterConfigItem )
    {
        mnMode = pFilterConfigItem->ReadInt32( "FileFormat", 0 );

        xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
        if ( xStatusIndicator.is() )
        {
            OUString aMsg;
            xStatusIndicator->start( aMsg, 100 );
        }
    }

    BitmapEx    aBmpEx( rGraphic.GetBitmapEx() );
    Bitmap      aBmp = aBmpEx.GetBitmap();
    aBmp.Convert( BMP_CONVERSION_1BIT_THRESHOLD );

    mpOStmOldModus = m_rOStm.GetNumberFormatInt();
    m_rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );

    mpAcc = aBmp.AcquireReadAccess();
    if( mpAcc )
    {
        if ( ImplWriteHeader() )
            ImplWriteBody();

        aBmp.ReleaseAccess( mpAcc );
    }
    else
        mbStatus = sal_False;

    m_rOStm.SetNumberFormatInt( mpOStmOldModus );

    if ( xStatusIndicator.is() )
        xStatusIndicator->end();

    return mbStatus;
}

sal_Bool PBMWriter::ImplWriteHeader()
{
    mnWidth = mpAcc->Width();
    mnHeight = mpAcc->Height();
    if ( mnWidth && mnHeight )
    {
        if ( mnMode == 0 )
            m_rOStm.WriteCharPtr( "P4\x0a" );
        else
            m_rOStm.WriteCharPtr( "P1\x0a" );

        ImplWriteNumber( mnWidth );
        m_rOStm.WriteUChar( (sal_uInt8)32 );
        ImplWriteNumber( mnHeight );
        m_rOStm.WriteUChar( (sal_uInt8)10 );
    }
    else mbStatus = sal_False;
    return mbStatus;
}

void PBMWriter::ImplWriteBody()
{
    if ( mnMode == 0 )
    {
        sal_uInt8   nBYTE = 0;
        for ( sal_uLong y = 0; y < mnHeight; y++ )
        {
            sal_uLong x;
            for ( x = 0; x < mnWidth; x++ )
            {
                nBYTE <<= 1;
                if (!(mpAcc->GetPixelIndex( y, x ) & 1 ) )
                    nBYTE++;
                if ( ( x & 7 ) == 7 )
                    m_rOStm.WriteUChar( nBYTE );
            }
            if ( ( x & 7 ) != 0 )
                m_rOStm.WriteUChar( (sal_uInt8)( nBYTE << ( ( x ^ 7 ) + 1 ) ) );
        }
    }
    else
    {
        int nxCount;
        for ( sal_uLong y = 0; y < mnHeight; y++ )
        {
            nxCount = 70;
            for ( sal_uLong x = 0; x < mnWidth; x++ )
            {
                if (!( --nxCount ) )
                {
                    nxCount = 69;
                    m_rOStm.WriteUChar( (sal_uInt8)10 );
                }
                m_rOStm.WriteUChar( (sal_uInt8)( ( mpAcc->GetPixelIndex( y, x ) ^ 1 ) + '0' ) ) ;
            }
            m_rOStm.WriteUChar( (sal_uInt8)10 );
        }
    }
}

// A decimal number in ascii format is written in the stream.

void PBMWriter::ImplWriteNumber(sal_Int32 nNumber)
{
    const OString aNum(OString::number(nNumber));
    m_rOStm.WriteCharPtr( aNum.getStr() );
}

// - exported function -

// this needs to be kept in sync with
// ImpFilterLibCacheEntry::GetImportFunction() from
// vcl/source/filter/graphicfilter.cxx
#if defined(DISABLE_DYNLOADING)
#define GraphicExport epbGraphicExport
#endif

extern "C" SAL_DLLPUBLIC_EXPORT bool SAL_CALL
GraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pFilterConfigItem )
{
    PBMWriter aPBMWriter(rStream);

    return aPBMWriter.WritePBM( rGraphic, pFilterConfigItem );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>coverity#738629 Uninitialized scalar field<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <vcl/svapp.hxx>
#include <vcl/graph.hxx>
#include <vcl/bmpacc.hxx>
#include <vcl/msgbox.hxx>
#include <svl/solar.hrc>
#include <vcl/fltcall.hxx>
#include <vcl/FilterConfigItem.hxx>

//============================ PBMWriter ==================================

class PBMWriter {

private:

    SvStream&           m_rOStm;            // the output PBM file
    sal_uInt16          mpOStmOldModus;

    sal_Bool            mbStatus;
    sal_Int32           mnMode;             // 0 -> raw, 1-> ascii
    BitmapReadAccess*   mpAcc;
    sal_uLong           mnWidth, mnHeight;  // size in pixel

    sal_Bool            ImplWriteHeader();
    void                ImplWriteBody();
    void                ImplWriteNumber( sal_Int32 );

    com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > xStatusIndicator;

public:
    PBMWriter(SvStream &rPBM);
    ~PBMWriter();

    sal_Bool WritePBM( const Graphic& rGraphic, FilterConfigItem* pFilterConfigItem );
};

//=================== Methods of PBMWriter ==============================

PBMWriter::PBMWriter(SvStream &rPBM)
    : m_rOStm(rPBM)
    , mpOStmOldModus(0)
    , mbStatus(sal_True)
    , mnMode(0)
    , mpAcc(NULL)
    , mnWidth(0)
    , mnHeight(0)
{
}

PBMWriter::~PBMWriter()
{
}

sal_Bool PBMWriter::WritePBM( const Graphic& rGraphic, FilterConfigItem* pFilterConfigItem )
{
    if ( pFilterConfigItem )
    {
        mnMode = pFilterConfigItem->ReadInt32( "FileFormat", 0 );

        xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
        if ( xStatusIndicator.is() )
        {
            OUString aMsg;
            xStatusIndicator->start( aMsg, 100 );
        }
    }

    BitmapEx    aBmpEx( rGraphic.GetBitmapEx() );
    Bitmap      aBmp = aBmpEx.GetBitmap();
    aBmp.Convert( BMP_CONVERSION_1BIT_THRESHOLD );

    mpOStmOldModus = m_rOStm.GetNumberFormatInt();
    m_rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );

    mpAcc = aBmp.AcquireReadAccess();
    if( mpAcc )
    {
        if ( ImplWriteHeader() )
            ImplWriteBody();

        aBmp.ReleaseAccess( mpAcc );
    }
    else
        mbStatus = sal_False;

    m_rOStm.SetNumberFormatInt( mpOStmOldModus );

    if ( xStatusIndicator.is() )
        xStatusIndicator->end();

    return mbStatus;
}

sal_Bool PBMWriter::ImplWriteHeader()
{
    mnWidth = mpAcc->Width();
    mnHeight = mpAcc->Height();
    if ( mnWidth && mnHeight )
    {
        if ( mnMode == 0 )
            m_rOStm.WriteCharPtr( "P4\x0a" );
        else
            m_rOStm.WriteCharPtr( "P1\x0a" );

        ImplWriteNumber( mnWidth );
        m_rOStm.WriteUChar( (sal_uInt8)32 );
        ImplWriteNumber( mnHeight );
        m_rOStm.WriteUChar( (sal_uInt8)10 );
    }
    else mbStatus = sal_False;
    return mbStatus;
}

void PBMWriter::ImplWriteBody()
{
    if ( mnMode == 0 )
    {
        sal_uInt8   nBYTE = 0;
        for ( sal_uLong y = 0; y < mnHeight; y++ )
        {
            sal_uLong x;
            for ( x = 0; x < mnWidth; x++ )
            {
                nBYTE <<= 1;
                if (!(mpAcc->GetPixelIndex( y, x ) & 1 ) )
                    nBYTE++;
                if ( ( x & 7 ) == 7 )
                    m_rOStm.WriteUChar( nBYTE );
            }
            if ( ( x & 7 ) != 0 )
                m_rOStm.WriteUChar( (sal_uInt8)( nBYTE << ( ( x ^ 7 ) + 1 ) ) );
        }
    }
    else
    {
        int nxCount;
        for ( sal_uLong y = 0; y < mnHeight; y++ )
        {
            nxCount = 70;
            for ( sal_uLong x = 0; x < mnWidth; x++ )
            {
                if (!( --nxCount ) )
                {
                    nxCount = 69;
                    m_rOStm.WriteUChar( (sal_uInt8)10 );
                }
                m_rOStm.WriteUChar( (sal_uInt8)( ( mpAcc->GetPixelIndex( y, x ) ^ 1 ) + '0' ) ) ;
            }
            m_rOStm.WriteUChar( (sal_uInt8)10 );
        }
    }
}

// A decimal number in ascii format is written in the stream.

void PBMWriter::ImplWriteNumber(sal_Int32 nNumber)
{
    const OString aNum(OString::number(nNumber));
    m_rOStm.WriteCharPtr( aNum.getStr() );
}

// - exported function -

// this needs to be kept in sync with
// ImpFilterLibCacheEntry::GetImportFunction() from
// vcl/source/filter/graphicfilter.cxx
#if defined(DISABLE_DYNLOADING)
#define GraphicExport epbGraphicExport
#endif

extern "C" SAL_DLLPUBLIC_EXPORT bool SAL_CALL
GraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pFilterConfigItem )
{
    PBMWriter aPBMWriter(rStream);

    return aPBMWriter.WritePBM( rGraphic, pFilterConfigItem );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before><commit_msg>tried D.cpp to 'D'<commit_after><|endoftext|>