<commit_before>// My library
#include "ModelToModelDistanceCLP.h"
#include <vtkDistancePolyDataFilter.h>
#include <vtkVersion.h>
#include <vtkPolyDataWriter.h>
#include <vtkXMLPolyDataWriter.h>
#include <vtkPolyDataReader.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkPolyData.h>
#include <vtkCommand.h>
#include <vtkPoints.h>
#include <vtkSmartPointer.h>
#include <vtkCleanPolyData.h>
#include <vtkTriangleFilter.h>
#include <vtkCellData.h>
#include <vtkPointData.h>
#include <vtkDoubleArray.h>
#include <vtkMath.h>
#include <vtkPolyDataNormals.h>
#include <vtkFloatArray.h>
#include <vtksys/SystemTools.hxx>

//class ErrorObserver copied from http://www.vtk.org/Wiki/VTK/Examples/Cxx/Utilities/ObserveError
class ErrorObserver : public vtkCommand
{
public:
    ErrorObserver():
        Error(false),
        Warning(false),
        ErrorMessage(""),
        WarningMessage("") {}
    static ErrorObserver *New()
    {
        return new ErrorObserver;
    }
    bool GetError() const
    {
        return this->Error;
    }
    bool GetWarning() const
    {
        return this->Warning;
    }
    void Clear()
    {
        this->Error = false;
        this->Warning = false;
        this->ErrorMessage = "";
        this->WarningMessage = "";
    }
    virtual void Execute(vtkObject *vtkNotUsed(caller),
                         unsigned long event,
                         void *calldata)
    {
        switch(event)
        {
        case vtkCommand::ErrorEvent:
            ErrorMessage = static_cast<char *>(calldata);
            this->Error = true;
            break;
        case vtkCommand::WarningEvent:
            WarningMessage = static_cast<char *>(calldata);
            this->Warning = true;
            break;
        }
    }
    std::string GetErrorMessage()
    {
        return ErrorMessage;
    }
    std::string GetWarningMessage()
    {
        return WarningMessage;
    }
private:
    bool        Error;
    bool        Warning;
    std::string ErrorMessage;
    std::string WarningMessage;
};

int TriangulateAndClean(vtkSmartPointer<vtkPolyData> &polyData )
{
    vtkSmartPointer <vtkCleanPolyData> Cleaner = vtkSmartPointer <vtkCleanPolyData>::New() ;
    Cleaner->SetInputData( polyData ) ;
    Cleaner->Update() ;
    vtkSmartPointer <vtkTriangleFilter> Triangler = vtkSmartPointer <vtkTriangleFilter>::New() ;
    Triangler->SetInputData( Cleaner->GetOutput() ) ;
    Triangler->Update() ;
    polyData = Triangler->GetOutput() ;
    return 0 ;
}

void PointsToVec( double p1[] , double p2[] , double vec[] )
{
    for( int i = 0 ; i < 3 ; i++ )
    {
        vec[ i ] = p2[ i ] - p1[ i ] ;
    }
}

int CorrespondingPointsDistance( vtkSmartPointer< vtkPolyData > &inPolyData1 ,
                                 vtkSmartPointer< vtkPolyData > &inPolyData2 ,
                                 std::string outputFieldSuffix
                                 )
{
    vtkIdType nbPoints1 = inPolyData1->GetNumberOfPoints() ;
    vtkIdType nbPoints2 = inPolyData2->GetNumberOfPoints() ;
    if( nbPoints1 != nbPoints2 )
    {
        std::cerr << "Both input files must have the same number of points to use \'corresponding_point_to_point\'" << std::endl ;
        return 1 ;
    }
    //Compute normals on inPolyData1
    vtkSmartPointer< vtkPolyDataNormals > normalGenerator = vtkSmartPointer<vtkPolyDataNormals>::New() ;
    normalGenerator->SetInputData( inPolyData1 ) ;
    normalGenerator->SplittingOff() ;
    normalGenerator->ComputePointNormalsOn() ;
    normalGenerator->ComputeCellNormalsOff() ;
    normalGenerator->Update() ;
    inPolyData1 = normalGenerator->GetOutput() ;
    //vtkSmartPointer< vtkDataSet > normals = inPolyData1->GetPointData()->GetArray( "Normals" ) ;
    vtkSmartPointer< vtkFloatArray > normalsArray = vtkFloatArray::SafeDownCast( inPolyData1->GetPointData()->GetNormals() ) ;
    /////////////////////////////////
    vtkSmartPointer <vtkDoubleArray> distanceArray = vtkSmartPointer <vtkDoubleArray>::New();
    std::string fieldName = "AbsolutePointToPointDistance" + outputFieldSuffix ;
    distanceArray->SetName( fieldName.c_str() ) ;
    vtkSmartPointer <vtkDoubleArray> distanceVecArray = vtkSmartPointer <vtkDoubleArray>::New();
    distanceVecArray->SetNumberOfComponents( 3 ) ;
    fieldName = "PointToPointVector" + outputFieldSuffix ;
    distanceVecArray->SetName( fieldName.c_str() ) ;
    vtkSmartPointer <vtkDoubleArray> signedDistanceArray = vtkSmartPointer <vtkDoubleArray>::New();
    fieldName = "SignedPointToPointDistance" + outputFieldSuffix ;
    signedDistanceArray->SetName( fieldName.c_str()) ;
    vtkSmartPointer <vtkDoubleArray> signedMagNormDirArray = vtkSmartPointer <vtkDoubleArray>::New();
    fieldName = "SignedMagNormDirDistance" + outputFieldSuffix ;
    signedMagNormDirArray->SetName( fieldName.c_str() ) ;
    vtkSmartPointer <vtkDoubleArray> magNormDirArray = vtkSmartPointer <vtkDoubleArray>::New();
    fieldName = "AbsoluteMagNormDirDistance" + outputFieldSuffix ;
    magNormDirArray->SetName( fieldName.c_str() ) ;
    vtkSmartPointer <vtkDoubleArray> magNormDirVecArray = vtkSmartPointer <vtkDoubleArray>::New();
    magNormDirVecArray->SetNumberOfComponents( 3 ) ;
    fieldName = "MagNormVector" + outputFieldSuffix ;
    magNormDirVecArray->SetName( fieldName.c_str() ) ;
    double absoluteDistance ;
    double* p1 ;
    double* p2 ;
    double vec[ 3 ] ;
    double* normal ;
    double dotProduct ;
    for( vtkIdType i = 0 ; i < nbPoints1 ; i++ )
    {
        p1 = inPolyData1->GetPoint( i ) ;
        p2 = inPolyData2->GetPoint( i ) ;
        PointsToVec( p1 , p2 , vec ) ;
        normal = normalsArray->GetTuple( i ) ;
        dotProduct = vtkMath::Dot( normal , vec ) ;
        //Signed and absolute corresponding point distance
        absoluteDistance = vtkMath::Norm( vec ) ;
        signedDistanceArray->InsertTuple1( i , ( dotProduct >= 0 ? absoluteDistance : -absoluteDistance ) ) ;
        distanceArray->InsertTuple1( i , absoluteDistance ) ;
        distanceVecArray->InsertTuple3( i , vec[ 0 ] , vec[ 1 ] , vec[ 2 ] ) ;
        //MagDir: projection of the distance vector on the normal
        signedMagNormDirArray->InsertTuple1( i , dotProduct ) ;
        magNormDirArray->InsertTuple1( i , ( dotProduct >= 0 ? dotProduct : -dotProduct ) ) ;
        for( int j = 0 ; j < 3 ; j++ )
        {
            normal[ j ] *= dotProduct ;
        }
        magNormDirVecArray->InsertTuple3( i , normal[ 0 ] , normal[ 1 ] , normal[ 2 ] ) ;
    }
    inPolyData1->GetPointData()->AddArray( distanceArray ) ;
    inPolyData1->GetPointData()->AddArray( magNormDirVecArray ) ;
    inPolyData1->GetPointData()->AddArray( distanceVecArray ) ;
    inPolyData1->GetPointData()->AddArray( signedDistanceArray ) ;
    inPolyData1->GetPointData()->AddArray( signedMagNormDirArray ) ;
    inPolyData1->GetPointData()->AddArray( magNormDirArray ) ;
    return 0 ;
}

int ClosestPointDistance( vtkSmartPointer< vtkPolyData > &inPolyData1 ,
                          vtkSmartPointer< vtkPolyData > &inPolyData2 ,
                          bool signedDistance ,
                          vtkSmartPointer< vtkPolyData > &outPolyData ,
                          std::string outputFieldSuffix
                          )
{
    vtkSmartPointer<vtkDistancePolyDataFilter> distanceFilter =
            vtkSmartPointer<vtkDistancePolyDataFilter>::New();
    distanceFilter->SetInputData( 0, inPolyData1 ) ;
    distanceFilter->SetInputData( 1, inPolyData2 ) ;
    distanceFilter->SetSignedDistance( signedDistance ) ;
    distanceFilter->Update();
    //We are only interested in the point distance, not in the cell distance, so we remove the cell distance
    distanceFilter->GetOutput()->GetCellData()->RemoveArray("Distance") ;
    //We rename the output array name to match the expected names in 3DMeshMetric
    std::string distanceName ;
    if( signedDistance )
    {
        distanceName = "Signed" + outputFieldSuffix ;
    }
    else
    {
        distanceName = "Absolute" + outputFieldSuffix;
    }
    distanceFilter->GetOutput()->GetPointData()->GetArray("Distance")->SetName(distanceName.c_str()) ;
    //We add a constant field that we call "original" that allows to show easily the model with no color map (constant color)
    vtkSmartPointer<vtkPolyData> distancePolyData = distanceFilter->GetOutput() ;
    vtkSmartPointer <vtkDoubleArray> ScalarsConst = vtkSmartPointer <vtkDoubleArray>::New();
    for( vtkIdType Id = 0 ; Id < distancePolyData->GetNumberOfPoints() ; Id++ )
    {
        ScalarsConst->InsertTuple1( Id , 1.0 );
    }
    ScalarsConst->SetName( "Original" );
    distancePolyData->GetPointData()->AddArray( ScalarsConst );
    vtkSmartPointer <vtkCleanPolyData> Cleaner = vtkSmartPointer <vtkCleanPolyData>::New() ;
    Cleaner->SetInputData( distancePolyData ) ;
    Cleaner->Update() ;
    outPolyData = Cleaner->GetOutput() ;
    return 0 ;
}

int ReadVTK( std::string input , vtkSmartPointer<vtkPolyData> &polyData )
{
    vtkSmartPointer<ErrorObserver>  errorObserver =
            vtkSmartPointer<ErrorObserver>::New();
    if( input.rfind( ".vtk" ) != std::string::npos )
    {
        vtkSmartPointer< vtkPolyDataReader > polyReader = vtkPolyDataReader::New() ;
        polyReader->AddObserver( vtkCommand::ErrorEvent , errorObserver ) ;
        polyReader->SetFileName( input.c_str() ) ;
        polyData = polyReader->GetOutput() ;
        polyReader->Update() ;
    }
    else if( input.rfind( ".vtp" ) != std::string::npos )
    {
        vtkSmartPointer< vtkXMLPolyDataReader > xmlReader = vtkXMLPolyDataReader::New() ;
        xmlReader->SetFileName( input.c_str() ) ;
        xmlReader->AddObserver( vtkCommand::ErrorEvent , errorObserver ) ;
        polyData = xmlReader->GetOutput() ;
        xmlReader->Update() ;
    }
    else
    {
        std::cerr << "Input file format not handled: " << input << " cannot be read" << std::endl ;
        return 1 ;
    }
    if (errorObserver->GetError())
    {
        std::cout << "Caught error opening " << input << std::endl ;
        return 1 ;
    }
    return 0 ;
}

int WriteVTK( std::string output , vtkSmartPointer<vtkPolyData> &polyData )
{
    vtkSmartPointer<ErrorObserver>  errorObserver =
            vtkSmartPointer<ErrorObserver>::New();
    if (output.rfind(".vtk") != std::string::npos )
    {
        vtkSmartPointer<vtkPolyDataWriter> writer = vtkPolyDataWriter::New() ;
        writer->SetFileName( output.c_str() ) ;
        writer->AddObserver( vtkCommand::ErrorEvent , errorObserver ) ;
        writer->SetInputData( polyData ) ;
        writer->Update();
    }
    else if( output.rfind( ".vtp" ) != std::string::npos )
    {
        vtkSmartPointer< vtkXMLPolyDataWriter > writer = vtkXMLPolyDataWriter::New() ;
        writer->SetFileName( output.c_str() ) ;
        writer->AddObserver( vtkCommand::ErrorEvent , errorObserver ) ;
        writer->SetInputData( polyData ) ;
        writer->Update() ;
    }
    else
    {
        std::cerr << "Output file format not handled: " << output << " cannot be written" << std::endl ;
        return 1 ;
    }
    if (errorObserver->GetError())
    {
        std::cout << "Caught error saving " << output << std::endl ;
        return 1 ;
    }
    return 0 ;
}

int main( int argc , char* argv[] )
{
    PARSE_ARGS ;
    if( vtkFile1.empty() || vtkFile2.empty() )
    {
        std::cout << "Specify 2 vtk input files" << std::endl ;
        return 1 ;
    }
    if( vtkOutput.empty() )
    {
        std::cout << "Specify an output file name" << std::endl ;
        return 1 ;
    }
    vtkSmartPointer<vtkPolyData> inPolyData1 = vtkSmartPointer<vtkPolyData>::New() ;
    if( ReadVTK( vtkFile1 , inPolyData1 ) )
    {
        return 1 ;
    }
    vtkSmartPointer<vtkPolyData> inPolyData2 = vtkSmartPointer<vtkPolyData>::New() ;
    if( ReadVTK( vtkFile2 , inPolyData2 ) )
    {
        return 1 ;
    }
    if( TriangulateAndClean( inPolyData1 ) )
    {
        return EXIT_FAILURE ;
    }
    if( TriangulateAndClean( inPolyData2 ) )
    {
        return EXIT_FAILURE ;
    }
    std::string outputFieldSuffix ;
    if( targetInFields )
    {
      outputFieldSuffix = "_to_" + vtksys::SystemTools::GetFilenameWithoutExtension( vtkFile2 ) ;
    }
    vtkSmartPointer< vtkPolyData > outPolyData ;
    if( distanceType == "corresponding_point_to_point" )
    {
        if( CorrespondingPointsDistance( inPolyData1 , inPolyData2 , outputFieldSuffix ) )
        {
            return EXIT_FAILURE ;
        }
        outPolyData = inPolyData1 ;
    }
    else
    {
        bool signedDistance = false ;
        if( distanceType == "signed_closest_point" )
        {
            signedDistance = true ;
        }
        if( ClosestPointDistance( inPolyData1 , inPolyData2 , signedDistance , outPolyData , outputFieldSuffix ) )
        {
            return EXIT_FAILURE ;
        }
    }
    return WriteVTK( vtkOutput , outPolyData ) ;
}
<commit_msg>ENH: When computing corresponding point distance, ModelToModelDistance now prints number of points of each model if their number of points do not match.<commit_after>// My library
#include "ModelToModelDistanceCLP.h"
#include <vtkDistancePolyDataFilter.h>
#include <vtkVersion.h>
#include <vtkPolyDataWriter.h>
#include <vtkXMLPolyDataWriter.h>
#include <vtkPolyDataReader.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkPolyData.h>
#include <vtkCommand.h>
#include <vtkPoints.h>
#include <vtkSmartPointer.h>
#include <vtkCleanPolyData.h>
#include <vtkTriangleFilter.h>
#include <vtkCellData.h>
#include <vtkPointData.h>
#include <vtkDoubleArray.h>
#include <vtkMath.h>
#include <vtkPolyDataNormals.h>
#include <vtkFloatArray.h>
#include <vtksys/SystemTools.hxx>

//class ErrorObserver copied from http://www.vtk.org/Wiki/VTK/Examples/Cxx/Utilities/ObserveError
class ErrorObserver : public vtkCommand
{
public:
    ErrorObserver():
        Error(false),
        Warning(false),
        ErrorMessage(""),
        WarningMessage("") {}
    static ErrorObserver *New()
    {
        return new ErrorObserver;
    }
    bool GetError() const
    {
        return this->Error;
    }
    bool GetWarning() const
    {
        return this->Warning;
    }
    void Clear()
    {
        this->Error = false;
        this->Warning = false;
        this->ErrorMessage = "";
        this->WarningMessage = "";
    }
    virtual void Execute(vtkObject *vtkNotUsed(caller),
                         unsigned long event,
                         void *calldata)
    {
        switch(event)
        {
        case vtkCommand::ErrorEvent:
            ErrorMessage = static_cast<char *>(calldata);
            this->Error = true;
            break;
        case vtkCommand::WarningEvent:
            WarningMessage = static_cast<char *>(calldata);
            this->Warning = true;
            break;
        }
    }
    std::string GetErrorMessage()
    {
        return ErrorMessage;
    }
    std::string GetWarningMessage()
    {
        return WarningMessage;
    }
private:
    bool        Error;
    bool        Warning;
    std::string ErrorMessage;
    std::string WarningMessage;
};

int TriangulateAndClean(vtkSmartPointer<vtkPolyData> &polyData )
{
    vtkSmartPointer <vtkCleanPolyData> Cleaner = vtkSmartPointer <vtkCleanPolyData>::New() ;
    Cleaner->SetInputData( polyData ) ;
    Cleaner->Update() ;
    vtkSmartPointer <vtkTriangleFilter> Triangler = vtkSmartPointer <vtkTriangleFilter>::New() ;
    Triangler->SetInputData( Cleaner->GetOutput() ) ;
    Triangler->Update() ;
    polyData = Triangler->GetOutput() ;
    return 0 ;
}

void PointsToVec( double p1[] , double p2[] , double vec[] )
{
    for( int i = 0 ; i < 3 ; i++ )
    {
        vec[ i ] = p2[ i ] - p1[ i ] ;
    }
}

int CorrespondingPointsDistance( vtkSmartPointer< vtkPolyData > &inPolyData1 ,
                                 vtkSmartPointer< vtkPolyData > &inPolyData2 ,
                                 std::string outputFieldSuffix
                                 )
{
    vtkIdType nbPoints1 = inPolyData1->GetNumberOfPoints() ;
    vtkIdType nbPoints2 = inPolyData2->GetNumberOfPoints() ;
    if( nbPoints1 != nbPoints2 )
    {
        std::cerr << "Both input files must have the same number of points to use \'corresponding_point_to_point\'" << std::endl ;
        std::cerr << "Source model has " << nbPoints1 << " points" << std::endl ;
        std::cerr << "Target model has " << nbPoints2 << " points" << std::endl ;
        return 1 ;
    }
    //Compute normals on inPolyData1
    vtkSmartPointer< vtkPolyDataNormals > normalGenerator = vtkSmartPointer<vtkPolyDataNormals>::New() ;
    normalGenerator->SetInputData( inPolyData1 ) ;
    normalGenerator->SplittingOff() ;
    normalGenerator->ComputePointNormalsOn() ;
    normalGenerator->ComputeCellNormalsOff() ;
    normalGenerator->Update() ;
    inPolyData1 = normalGenerator->GetOutput() ;
    //vtkSmartPointer< vtkDataSet > normals = inPolyData1->GetPointData()->GetArray( "Normals" ) ;
    vtkSmartPointer< vtkFloatArray > normalsArray = vtkFloatArray::SafeDownCast( inPolyData1->GetPointData()->GetNormals() ) ;
    /////////////////////////////////
    vtkSmartPointer <vtkDoubleArray> distanceArray = vtkSmartPointer <vtkDoubleArray>::New();
    std::string fieldName = "AbsolutePointToPointDistance" + outputFieldSuffix ;
    distanceArray->SetName( fieldName.c_str() ) ;
    vtkSmartPointer <vtkDoubleArray> distanceVecArray = vtkSmartPointer <vtkDoubleArray>::New();
    distanceVecArray->SetNumberOfComponents( 3 ) ;
    fieldName = "PointToPointVector" + outputFieldSuffix ;
    distanceVecArray->SetName( fieldName.c_str() ) ;
    vtkSmartPointer <vtkDoubleArray> signedDistanceArray = vtkSmartPointer <vtkDoubleArray>::New();
    fieldName = "SignedPointToPointDistance" + outputFieldSuffix ;
    signedDistanceArray->SetName( fieldName.c_str()) ;
    vtkSmartPointer <vtkDoubleArray> signedMagNormDirArray = vtkSmartPointer <vtkDoubleArray>::New();
    fieldName = "SignedMagNormDirDistance" + outputFieldSuffix ;
    signedMagNormDirArray->SetName( fieldName.c_str() ) ;
    vtkSmartPointer <vtkDoubleArray> magNormDirArray = vtkSmartPointer <vtkDoubleArray>::New();
    fieldName = "AbsoluteMagNormDirDistance" + outputFieldSuffix ;
    magNormDirArray->SetName( fieldName.c_str() ) ;
    vtkSmartPointer <vtkDoubleArray> magNormDirVecArray = vtkSmartPointer <vtkDoubleArray>::New();
    magNormDirVecArray->SetNumberOfComponents( 3 ) ;
    fieldName = "MagNormVector" + outputFieldSuffix ;
    magNormDirVecArray->SetName( fieldName.c_str() ) ;
    double absoluteDistance ;
    double* p1 ;
    double* p2 ;
    double vec[ 3 ] ;
    double* normal ;
    double dotProduct ;
    for( vtkIdType i = 0 ; i < nbPoints1 ; i++ )
    {
        p1 = inPolyData1->GetPoint( i ) ;
        p2 = inPolyData2->GetPoint( i ) ;
        PointsToVec( p1 , p2 , vec ) ;
        normal = normalsArray->GetTuple( i ) ;
        dotProduct = vtkMath::Dot( normal , vec ) ;
        //Signed and absolute corresponding point distance
        absoluteDistance = vtkMath::Norm( vec ) ;
        signedDistanceArray->InsertTuple1( i , ( dotProduct >= 0 ? absoluteDistance : -absoluteDistance ) ) ;
        distanceArray->InsertTuple1( i , absoluteDistance ) ;
        distanceVecArray->InsertTuple3( i , vec[ 0 ] , vec[ 1 ] , vec[ 2 ] ) ;
        //MagDir: projection of the distance vector on the normal
        signedMagNormDirArray->InsertTuple1( i , dotProduct ) ;
        magNormDirArray->InsertTuple1( i , ( dotProduct >= 0 ? dotProduct : -dotProduct ) ) ;
        for( int j = 0 ; j < 3 ; j++ )
        {
            normal[ j ] *= dotProduct ;
        }
        magNormDirVecArray->InsertTuple3( i , normal[ 0 ] , normal[ 1 ] , normal[ 2 ] ) ;
    }
    inPolyData1->GetPointData()->AddArray( distanceArray ) ;
    inPolyData1->GetPointData()->AddArray( magNormDirVecArray ) ;
    inPolyData1->GetPointData()->AddArray( distanceVecArray ) ;
    inPolyData1->GetPointData()->AddArray( signedDistanceArray ) ;
    inPolyData1->GetPointData()->AddArray( signedMagNormDirArray ) ;
    inPolyData1->GetPointData()->AddArray( magNormDirArray ) ;
    return 0 ;
}

int ClosestPointDistance( vtkSmartPointer< vtkPolyData > &inPolyData1 ,
                          vtkSmartPointer< vtkPolyData > &inPolyData2 ,
                          bool signedDistance ,
                          vtkSmartPointer< vtkPolyData > &outPolyData ,
                          std::string outputFieldSuffix
                          )
{
    vtkSmartPointer<vtkDistancePolyDataFilter> distanceFilter =
            vtkSmartPointer<vtkDistancePolyDataFilter>::New();
    distanceFilter->SetInputData( 0, inPolyData1 ) ;
    distanceFilter->SetInputData( 1, inPolyData2 ) ;
    distanceFilter->SetSignedDistance( signedDistance ) ;
    distanceFilter->Update();
    //We are only interested in the point distance, not in the cell distance, so we remove the cell distance
    distanceFilter->GetOutput()->GetCellData()->RemoveArray("Distance") ;
    //We rename the output array name to match the expected names in 3DMeshMetric
    std::string distanceName ;
    if( signedDistance )
    {
        distanceName = "Signed" + outputFieldSuffix ;
    }
    else
    {
        distanceName = "Absolute" + outputFieldSuffix;
    }
    distanceFilter->GetOutput()->GetPointData()->GetArray("Distance")->SetName(distanceName.c_str()) ;
    //We add a constant field that we call "original" that allows to show easily the model with no color map (constant color)
    vtkSmartPointer<vtkPolyData> distancePolyData = distanceFilter->GetOutput() ;
    vtkSmartPointer <vtkDoubleArray> ScalarsConst = vtkSmartPointer <vtkDoubleArray>::New();
    for( vtkIdType Id = 0 ; Id < distancePolyData->GetNumberOfPoints() ; Id++ )
    {
        ScalarsConst->InsertTuple1( Id , 1.0 );
    }
    ScalarsConst->SetName( "Original" );
    distancePolyData->GetPointData()->AddArray( ScalarsConst );
    vtkSmartPointer <vtkCleanPolyData> Cleaner = vtkSmartPointer <vtkCleanPolyData>::New() ;
    Cleaner->SetInputData( distancePolyData ) ;
    Cleaner->Update() ;
    outPolyData = Cleaner->GetOutput() ;
    return 0 ;
}

int ReadVTK( std::string input , vtkSmartPointer<vtkPolyData> &polyData )
{
    vtkSmartPointer<ErrorObserver>  errorObserver =
            vtkSmartPointer<ErrorObserver>::New();
    if( input.rfind( ".vtk" ) != std::string::npos )
    {
        vtkSmartPointer< vtkPolyDataReader > polyReader = vtkPolyDataReader::New() ;
        polyReader->AddObserver( vtkCommand::ErrorEvent , errorObserver ) ;
        polyReader->SetFileName( input.c_str() ) ;
        polyData = polyReader->GetOutput() ;
        polyReader->Update() ;
    }
    else if( input.rfind( ".vtp" ) != std::string::npos )
    {
        vtkSmartPointer< vtkXMLPolyDataReader > xmlReader = vtkXMLPolyDataReader::New() ;
        xmlReader->SetFileName( input.c_str() ) ;
        xmlReader->AddObserver( vtkCommand::ErrorEvent , errorObserver ) ;
        polyData = xmlReader->GetOutput() ;
        xmlReader->Update() ;
    }
    else
    {
        std::cerr << "Input file format not handled: " << input << " cannot be read" << std::endl ;
        return 1 ;
    }
    if (errorObserver->GetError())
    {
        std::cout << "Caught error opening " << input << std::endl ;
        return 1 ;
    }
    return 0 ;
}

int WriteVTK( std::string output , vtkSmartPointer<vtkPolyData> &polyData )
{
    vtkSmartPointer<ErrorObserver>  errorObserver =
            vtkSmartPointer<ErrorObserver>::New();
    if (output.rfind(".vtk") != std::string::npos )
    {
        vtkSmartPointer<vtkPolyDataWriter> writer = vtkPolyDataWriter::New() ;
        writer->SetFileName( output.c_str() ) ;
        writer->AddObserver( vtkCommand::ErrorEvent , errorObserver ) ;
        writer->SetInputData( polyData ) ;
        writer->Update();
    }
    else if( output.rfind( ".vtp" ) != std::string::npos )
    {
        vtkSmartPointer< vtkXMLPolyDataWriter > writer = vtkXMLPolyDataWriter::New() ;
        writer->SetFileName( output.c_str() ) ;
        writer->AddObserver( vtkCommand::ErrorEvent , errorObserver ) ;
        writer->SetInputData( polyData ) ;
        writer->Update() ;
    }
    else
    {
        std::cerr << "Output file format not handled: " << output << " cannot be written" << std::endl ;
        return 1 ;
    }
    if (errorObserver->GetError())
    {
        std::cout << "Caught error saving " << output << std::endl ;
        return 1 ;
    }
    return 0 ;
}

int main( int argc , char* argv[] )
{
    PARSE_ARGS ;
    if( vtkFile1.empty() || vtkFile2.empty() )
    {
        std::cout << "Specify 2 vtk input files" << std::endl ;
        return 1 ;
    }
    if( vtkOutput.empty() )
    {
        std::cout << "Specify an output file name" << std::endl ;
        return 1 ;
    }
    vtkSmartPointer<vtkPolyData> inPolyData1 = vtkSmartPointer<vtkPolyData>::New() ;
    if( ReadVTK( vtkFile1 , inPolyData1 ) )
    {
        return 1 ;
    }
    vtkSmartPointer<vtkPolyData> inPolyData2 = vtkSmartPointer<vtkPolyData>::New() ;
    if( ReadVTK( vtkFile2 , inPolyData2 ) )
    {
        return 1 ;
    }
    if( TriangulateAndClean( inPolyData1 ) )
    {
        return EXIT_FAILURE ;
    }
    if( TriangulateAndClean( inPolyData2 ) )
    {
        return EXIT_FAILURE ;
    }
    std::string outputFieldSuffix ;
    if( targetInFields )
    {
      outputFieldSuffix = "_to_" + vtksys::SystemTools::GetFilenameWithoutExtension( vtkFile2 ) ;
    }
    vtkSmartPointer< vtkPolyData > outPolyData ;
    if( distanceType == "corresponding_point_to_point" )
    {
        if( CorrespondingPointsDistance( inPolyData1 , inPolyData2 , outputFieldSuffix ) )
        {
            return EXIT_FAILURE ;
        }
        outPolyData = inPolyData1 ;
    }
    else
    {
        bool signedDistance = false ;
        if( distanceType == "signed_closest_point" )
        {
            signedDistance = true ;
        }
        if( ClosestPointDistance( inPolyData1 , inPolyData2 , signedDistance , outPolyData , outputFieldSuffix ) )
        {
            return EXIT_FAILURE ;
        }
    }
    return WriteVTK( vtkOutput , outPolyData ) ;
}
<|endoftext|>


<commit_before>/*
  This file is part of Ingen.
  Copyright 2007-2015 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

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

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ingen/Interface.hpp"
#include "ingen/Log.hpp"
#include "ingen/URIs.hpp"
#include "ingen/client/BlockModel.hpp"
#include "ingen/client/PluginUI.hpp"
#include "ingen/client/PortModel.hpp"
#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"

using namespace std;

namespace Ingen {
namespace Client {

SuilHost* PluginUI::ui_host = NULL;

static SPtr<const PortModel>
get_port(PluginUI* ui, uint32_t port_index)
{
	if (port_index >= ui->block()->ports().size()) {
		ui->world()->log().error(
			fmt("%1% UI tried to access invalid port %2%\n")
			% ui->block()->plugin()->uri().c_str() % port_index);
		return SPtr<const PortModel>();
	}
	return ui->block()->ports()[port_index];
}

static void
lv2_ui_write(SuilController controller,
             uint32_t       port_index,
             uint32_t       buffer_size,
             uint32_t       format,
             const void*    buffer)
{
	PluginUI* const       ui   = (PluginUI*)controller;
	const URIs&           uris = ui->world()->uris();
	SPtr<const PortModel> port = get_port(ui, port_index);
	if (!port) {
		return;
	}

	// float (special case, always 0)
	if (format == 0) {
		if (buffer_size != 4) {
			ui->world()->log().error(
				fmt("%1% UI wrote corrupt float with bad size\n")
				% ui->block()->plugin()->uri().c_str());
			return;
		}
		const float value = *(const float*)buffer;
		if (port->value().type() == uris.atom_Float &&
		    value == port->value().get<float>()) {
			return;  // Ignore feedback
		}

		ui->signal_property_changed()(
			port->uri(),
			uris.ingen_value,
			ui->world()->forge().make(value));

	} else if (format == uris.atom_eventTransfer.urid.get<LV2_URID>()) {
		const LV2_Atom* atom = (const LV2_Atom*)buffer;
		Atom            val  = ui->world()->forge().alloc(
			atom->size, atom->type, LV2_ATOM_BODY_CONST(atom));
		ui->signal_property_changed()(port->uri(),
		                              uris.ingen_activity,
		                              val);

	} else {
		ui->world()->log().warn(
			fmt("Unknown value format %1% from LV2 UI\n")
			% format % ui->block()->plugin()->uri().c_str());
	}
}

static uint32_t
lv2_ui_port_index(SuilController controller, const char* port_symbol)
{
	PluginUI* const ui = (PluginUI*)controller;

	const BlockModel::Ports& ports = ui->block()->ports();
	for (uint32_t i = 0; i < ports.size(); ++i) {
		if (ports[i]->symbol() == port_symbol) {
			return i;
		}
	}
	return LV2UI_INVALID_PORT_INDEX;
}

static uint32_t
lv2_ui_subscribe(SuilController            controller,
                 uint32_t                  port_index,
                 uint32_t                  protocol,
                 const LV2_Feature* const* features)
{
	PluginUI* const       ui   = (PluginUI*)controller;
	SPtr<const PortModel> port = get_port(ui, port_index);
	if (!port) {
		return 1;
	}

	ui->signal_property_changed()(
		ui->block()->ports()[port_index]->uri(),
		ui->world()->uris().ingen_broadcast,
		ui->world()->forge().make(true));

	return 0;
}

static uint32_t
lv2_ui_unsubscribe(SuilController            controller,
                   uint32_t                  port_index,
                   uint32_t                  protocol,
                   const LV2_Feature* const* features)
{
	PluginUI* const       ui   = (PluginUI*)controller;
	SPtr<const PortModel> port = get_port(ui, port_index);
	if (!port) {
		return 1;
	}

	ui->signal_property_changed()(
		ui->block()->ports()[port_index]->uri(),
		ui->world()->uris().ingen_broadcast,
		ui->world()->forge().make(false));

	return 0;
}

PluginUI::PluginUI(Ingen::World*          world,
                   SPtr<const BlockModel> block,
                   LilvUIs*               uis,
                   const LilvUI*          ui,
                   const LilvNode*        ui_type)
	: _world(world)
	, _block(block)
	, _instance(NULL)
	, _uis(uis)
	, _ui(ui)
	, _ui_node(lilv_node_duplicate(lilv_ui_get_uri(ui)))
	, _ui_type(lilv_node_duplicate(ui_type))
{
}

PluginUI::~PluginUI()
{
	for (uint32_t i : _subscribed_ports) {
		lv2_ui_unsubscribe(this, i, 0, NULL);
	}
	suil_instance_free(_instance);
	lilv_node_free(_ui_node);
	lilv_node_free(_ui_type);
	lilv_uis_free(_uis);
}

SPtr<PluginUI>
PluginUI::create(Ingen::World*          world,
                 SPtr<const BlockModel> block,
                 const LilvPlugin*      plugin)
{
	if (!PluginUI::ui_host) {
		PluginUI::ui_host = suil_host_new(lv2_ui_write,
		                                  lv2_ui_port_index,
		                                  lv2_ui_subscribe,
		                                  lv2_ui_unsubscribe);
	}

	static const char* gtk_ui_uri = LV2_UI__GtkUI;

	LilvNode* gtk_ui = lilv_new_uri(world->lilv_world(), gtk_ui_uri);

	LilvUIs*        uis     = lilv_plugin_get_uis(plugin);
	const LilvUI*   ui      = NULL;
	const LilvNode* ui_type = NULL;
	LILV_FOREACH(uis, u, uis) {
		const LilvUI* this_ui = lilv_uis_get(uis, u);
		if (lilv_ui_is_supported(this_ui,
		                         suil_ui_supported,
		                         gtk_ui,
		                         &ui_type)) {
			// TODO: Multiple UI support
			ui = this_ui;
			break;
		}
	}

	if (!ui) {
		lilv_node_free(gtk_ui);
		return SPtr<PluginUI>();
	}

	// Create the PluginUI, but don't instantiate yet
	SPtr<PluginUI> ret(new PluginUI(world, block, uis, ui, ui_type));
	ret->_features = world->lv2_features().lv2_features(
		world, const_cast<BlockModel*>(block.get()));

	return ret;
}

bool
PluginUI::instantiate()
{
	const URIs&       uris       = _world->uris();
	const std::string plugin_uri = _block->plugin()->uri();

	/* Subscribe (enable broadcast) for any requested port notifications.  This
	   must be done before instantiation so responses to any events sent by the
	   UI's init() will be sent back to this client. */
	LilvWorld* lworld              = _world->lilv_world();
	LilvNode*  ui_portNotification = lilv_new_uri(lworld, LV2_UI__portNotification);
	LilvNode*  ui_plugin           = lilv_new_uri(lworld, LV2_UI__plugin);
	LilvNodes* notes               = lilv_world_find_nodes(
		lworld, lilv_ui_get_uri(_ui), ui_portNotification, NULL);
	LILV_FOREACH(nodes, n, notes) {
		const LilvNode* note = lilv_nodes_get(notes, n);
		const LilvNode* sym  = lilv_world_get(lworld, note, uris.lv2_symbol, NULL);
		const LilvNode* plug = lilv_world_get(lworld, note, ui_plugin, NULL);
		if (!plug) {
			_world->log().error(fmt("%1% UI %2% notification missing plugin\n")
			                    % plugin_uri % lilv_node_as_string(_ui_node));
		} else if (!sym) {
			_world->log().error(fmt("%1% UI %2% notification missing symbol\n")
			                    % plugin_uri % lilv_node_as_string(_ui_node));
		} else if (!lilv_node_is_uri(plug)) {
			_world->log().error(fmt("%1% UI %2% notification has non-URI plugin\n")
			                    % plugin_uri % lilv_node_as_string(_ui_node));
		} else if (!strcmp(lilv_node_as_uri(plug), plugin_uri.c_str())) {
			// Notification is valid and for this plugin
			uint32_t index = lv2_ui_port_index(this, lilv_node_as_string(sym));
			if (index != LV2UI_INVALID_PORT_INDEX) {
				lv2_ui_subscribe(this, index, 0, NULL);
				_subscribed_ports.insert(index);
			}
		}
	}
	lilv_nodes_free(notes);
	lilv_node_free(ui_plugin);
	lilv_node_free(ui_portNotification);

	const char* bundle_uri  = lilv_node_as_uri(lilv_ui_get_bundle_uri(_ui));
	const char* binary_uri  = lilv_node_as_uri(lilv_ui_get_binary_uri(_ui));
	char*       bundle_path = lilv_file_uri_parse(bundle_uri, NULL);
	char*       binary_path = lilv_file_uri_parse(binary_uri, NULL);

	// Instantiate the actual plugin UI via Suil
	_instance = suil_instance_new(
		PluginUI::ui_host,
		this,
		LV2_UI__GtkUI,
		plugin_uri.c_str(),
		lilv_node_as_uri(lilv_ui_get_uri(_ui)),
		lilv_node_as_uri(_ui_type),
		bundle_path,
		binary_path,
		_features->array());

	lilv_free(binary_path);
	lilv_free(bundle_path);

	if (!_instance) {
		_world->log().error("Failed to instantiate LV2 UI\n");
		// Cancel any subscriptions
		for (uint32_t i : _subscribed_ports) {
			lv2_ui_unsubscribe(this, i, 0, NULL);
		}
		return false;
	}

	return true;
}

SuilWidget
PluginUI::get_widget()
{
	return (SuilWidget*)suil_instance_get_widget(_instance);
}

void
PluginUI::port_event(uint32_t    port_index,
                     uint32_t    buffer_size,
                     uint32_t    format,
                     const void* buffer)
{
	if (_instance) {
		suil_instance_port_event(
			_instance, port_index, buffer_size, format, buffer);
	} else {
		_world->log().warn("LV2 UI port event with no instance\n");
	}
}

bool
PluginUI::is_resizable() const
{
	LilvWorld*      w   = _world->lilv_world();
	const LilvNode* s   = _ui_node;
	LilvNode*       p   = lilv_new_uri(w, LV2_CORE__optionalFeature);
	LilvNode*       fs  = lilv_new_uri(w, LV2_UI__fixedSize);
	LilvNode*       nrs = lilv_new_uri(w, LV2_UI__noUserResize);

	LilvNodes* fs_matches = lilv_world_find_nodes(w, s, p, fs);
	LilvNodes* nrs_matches = lilv_world_find_nodes(w, s, p, nrs);

	lilv_nodes_free(nrs_matches);
	lilv_nodes_free(fs_matches);
	lilv_node_free(nrs);
	lilv_node_free(fs);
	lilv_node_free(p);

	return !fs_matches && !nrs_matches;
}

} // namespace Client
} // namespace Ingen
<commit_msg>Fix loading UIs with separate data files<commit_after>/*
  This file is part of Ingen.
  Copyright 2007-2015 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

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

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ingen/Interface.hpp"
#include "ingen/Log.hpp"
#include "ingen/URIs.hpp"
#include "ingen/client/BlockModel.hpp"
#include "ingen/client/PluginUI.hpp"
#include "ingen/client/PortModel.hpp"
#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"

using namespace std;

namespace Ingen {
namespace Client {

SuilHost* PluginUI::ui_host = NULL;

static SPtr<const PortModel>
get_port(PluginUI* ui, uint32_t port_index)
{
	if (port_index >= ui->block()->ports().size()) {
		ui->world()->log().error(
			fmt("%1% UI tried to access invalid port %2%\n")
			% ui->block()->plugin()->uri().c_str() % port_index);
		return SPtr<const PortModel>();
	}
	return ui->block()->ports()[port_index];
}

static void
lv2_ui_write(SuilController controller,
             uint32_t       port_index,
             uint32_t       buffer_size,
             uint32_t       format,
             const void*    buffer)
{
	PluginUI* const       ui   = (PluginUI*)controller;
	const URIs&           uris = ui->world()->uris();
	SPtr<const PortModel> port = get_port(ui, port_index);
	if (!port) {
		return;
	}

	// float (special case, always 0)
	if (format == 0) {
		if (buffer_size != 4) {
			ui->world()->log().error(
				fmt("%1% UI wrote corrupt float with bad size\n")
				% ui->block()->plugin()->uri().c_str());
			return;
		}
		const float value = *(const float*)buffer;
		if (port->value().type() == uris.atom_Float &&
		    value == port->value().get<float>()) {
			return;  // Ignore feedback
		}

		ui->signal_property_changed()(
			port->uri(),
			uris.ingen_value,
			ui->world()->forge().make(value));

	} else if (format == uris.atom_eventTransfer.urid.get<LV2_URID>()) {
		const LV2_Atom* atom = (const LV2_Atom*)buffer;
		Atom            val  = ui->world()->forge().alloc(
			atom->size, atom->type, LV2_ATOM_BODY_CONST(atom));
		ui->signal_property_changed()(port->uri(),
		                              uris.ingen_activity,
		                              val);

	} else {
		ui->world()->log().warn(
			fmt("Unknown value format %1% from LV2 UI\n")
			% format % ui->block()->plugin()->uri().c_str());
	}
}

static uint32_t
lv2_ui_port_index(SuilController controller, const char* port_symbol)
{
	PluginUI* const ui = (PluginUI*)controller;

	const BlockModel::Ports& ports = ui->block()->ports();
	for (uint32_t i = 0; i < ports.size(); ++i) {
		if (ports[i]->symbol() == port_symbol) {
			return i;
		}
	}
	return LV2UI_INVALID_PORT_INDEX;
}

static uint32_t
lv2_ui_subscribe(SuilController            controller,
                 uint32_t                  port_index,
                 uint32_t                  protocol,
                 const LV2_Feature* const* features)
{
	PluginUI* const       ui   = (PluginUI*)controller;
	SPtr<const PortModel> port = get_port(ui, port_index);
	if (!port) {
		return 1;
	}

	ui->signal_property_changed()(
		ui->block()->ports()[port_index]->uri(),
		ui->world()->uris().ingen_broadcast,
		ui->world()->forge().make(true));

	return 0;
}

static uint32_t
lv2_ui_unsubscribe(SuilController            controller,
                   uint32_t                  port_index,
                   uint32_t                  protocol,
                   const LV2_Feature* const* features)
{
	PluginUI* const       ui   = (PluginUI*)controller;
	SPtr<const PortModel> port = get_port(ui, port_index);
	if (!port) {
		return 1;
	}

	ui->signal_property_changed()(
		ui->block()->ports()[port_index]->uri(),
		ui->world()->uris().ingen_broadcast,
		ui->world()->forge().make(false));

	return 0;
}

PluginUI::PluginUI(Ingen::World*          world,
                   SPtr<const BlockModel> block,
                   LilvUIs*               uis,
                   const LilvUI*          ui,
                   const LilvNode*        ui_type)
	: _world(world)
	, _block(block)
	, _instance(NULL)
	, _uis(uis)
	, _ui(ui)
	, _ui_node(lilv_node_duplicate(lilv_ui_get_uri(ui)))
	, _ui_type(lilv_node_duplicate(ui_type))
{
}

PluginUI::~PluginUI()
{
	for (uint32_t i : _subscribed_ports) {
		lv2_ui_unsubscribe(this, i, 0, NULL);
	}
	suil_instance_free(_instance);
	lilv_node_free(_ui_node);
	lilv_node_free(_ui_type);
	lilv_uis_free(_uis);
	lilv_world_unload_resource(_world->lilv_world(), lilv_ui_get_uri(_ui));
}

SPtr<PluginUI>
PluginUI::create(Ingen::World*          world,
                 SPtr<const BlockModel> block,
                 const LilvPlugin*      plugin)
{
	if (!PluginUI::ui_host) {
		PluginUI::ui_host = suil_host_new(lv2_ui_write,
		                                  lv2_ui_port_index,
		                                  lv2_ui_subscribe,
		                                  lv2_ui_unsubscribe);
	}

	static const char* gtk_ui_uri = LV2_UI__GtkUI;

	LilvNode* gtk_ui = lilv_new_uri(world->lilv_world(), gtk_ui_uri);

	LilvUIs*        uis     = lilv_plugin_get_uis(plugin);
	const LilvUI*   ui      = NULL;
	const LilvNode* ui_type = NULL;
	LILV_FOREACH(uis, u, uis) {
		const LilvUI* this_ui = lilv_uis_get(uis, u);
		if (lilv_ui_is_supported(this_ui,
		                         suil_ui_supported,
		                         gtk_ui,
		                         &ui_type)) {
			// TODO: Multiple UI support
			ui = this_ui;
			break;
		}
	}

	if (!ui) {
		lilv_node_free(gtk_ui);
		return SPtr<PluginUI>();
	}

	// Create the PluginUI, but don't instantiate yet
	SPtr<PluginUI> ret(new PluginUI(world, block, uis, ui, ui_type));
	ret->_features = world->lv2_features().lv2_features(
		world, const_cast<BlockModel*>(block.get()));

	return ret;
}

bool
PluginUI::instantiate()
{
	const URIs&       uris       = _world->uris();
	const std::string plugin_uri = _block->plugin()->uri();
	LilvWorld*        lworld     = _world->lilv_world();

	// Load seeAlso files to access data like portNotification descriptions
	lilv_world_load_resource(lworld, lilv_ui_get_uri(_ui));

	/* Subscribe (enable broadcast) for any requested port notifications.  This
	   must be done before instantiation so responses to any events sent by the
	   UI's init() will be sent back to this client. */
	LilvNode*  ui_portNotification = lilv_new_uri(lworld, LV2_UI__portNotification);
	LilvNode*  ui_plugin           = lilv_new_uri(lworld, LV2_UI__plugin);
	LilvNodes* notes               = lilv_world_find_nodes(
		lworld, lilv_ui_get_uri(_ui), ui_portNotification, NULL);
	LILV_FOREACH(nodes, n, notes) {
		const LilvNode* note = lilv_nodes_get(notes, n);
		const LilvNode* sym  = lilv_world_get(lworld, note, uris.lv2_symbol, NULL);
		const LilvNode* plug = lilv_world_get(lworld, note, ui_plugin, NULL);
		if (!plug) {
			_world->log().error(fmt("%1% UI %2% notification missing plugin\n")
			                    % plugin_uri % lilv_node_as_string(_ui_node));
		} else if (!sym) {
			_world->log().error(fmt("%1% UI %2% notification missing symbol\n")
			                    % plugin_uri % lilv_node_as_string(_ui_node));
		} else if (!lilv_node_is_uri(plug)) {
			_world->log().error(fmt("%1% UI %2% notification has non-URI plugin\n")
			                    % plugin_uri % lilv_node_as_string(_ui_node));
		} else if (!strcmp(lilv_node_as_uri(plug), plugin_uri.c_str())) {
			// Notification is valid and for this plugin
			uint32_t index = lv2_ui_port_index(this, lilv_node_as_string(sym));
			if (index != LV2UI_INVALID_PORT_INDEX) {
				lv2_ui_subscribe(this, index, 0, NULL);
				_subscribed_ports.insert(index);
			}
		}
	}
	lilv_nodes_free(notes);
	lilv_node_free(ui_plugin);
	lilv_node_free(ui_portNotification);

	const char* bundle_uri  = lilv_node_as_uri(lilv_ui_get_bundle_uri(_ui));
	const char* binary_uri  = lilv_node_as_uri(lilv_ui_get_binary_uri(_ui));
	char*       bundle_path = lilv_file_uri_parse(bundle_uri, NULL);
	char*       binary_path = lilv_file_uri_parse(binary_uri, NULL);

	// Instantiate the actual plugin UI via Suil
	_instance = suil_instance_new(
		PluginUI::ui_host,
		this,
		LV2_UI__GtkUI,
		plugin_uri.c_str(),
		lilv_node_as_uri(lilv_ui_get_uri(_ui)),
		lilv_node_as_uri(_ui_type),
		bundle_path,
		binary_path,
		_features->array());

	lilv_free(binary_path);
	lilv_free(bundle_path);

	if (!_instance) {
		_world->log().error("Failed to instantiate LV2 UI\n");
		// Cancel any subscriptions
		for (uint32_t i : _subscribed_ports) {
			lv2_ui_unsubscribe(this, i, 0, NULL);
		}
		return false;
	}

	return true;
}

SuilWidget
PluginUI::get_widget()
{
	return (SuilWidget*)suil_instance_get_widget(_instance);
}

void
PluginUI::port_event(uint32_t    port_index,
                     uint32_t    buffer_size,
                     uint32_t    format,
                     const void* buffer)
{
	if (_instance) {
		suil_instance_port_event(
			_instance, port_index, buffer_size, format, buffer);
	} else {
		_world->log().warn("LV2 UI port event with no instance\n");
	}
}

bool
PluginUI::is_resizable() const
{
	LilvWorld*      w   = _world->lilv_world();
	const LilvNode* s   = _ui_node;
	LilvNode*       p   = lilv_new_uri(w, LV2_CORE__optionalFeature);
	LilvNode*       fs  = lilv_new_uri(w, LV2_UI__fixedSize);
	LilvNode*       nrs = lilv_new_uri(w, LV2_UI__noUserResize);

	LilvNodes* fs_matches = lilv_world_find_nodes(w, s, p, fs);
	LilvNodes* nrs_matches = lilv_world_find_nodes(w, s, p, nrs);

	lilv_nodes_free(nrs_matches);
	lilv_nodes_free(fs_matches);
	lilv_node_free(nrs);
	lilv_node_free(fs);
	lilv_node_free(p);

	return !fs_matches && !nrs_matches;
}

} // namespace Client
} // namespace Ingen
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed 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.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef itkVideoSource_hxx
#define itkVideoSource_hxx

#include "itkVideoSource.h"

namespace itk
{

//-CONSTRUCTOR PRINT-----------------------------------------------------------

//
// Constructor
//
template<typename TOutputVideoStream>
VideoSource<TOutputVideoStream>::VideoSource()
{
  typename OutputVideoStreamType::Pointer output =
    static_cast< OutputVideoStreamType* >( this->MakeOutput(0).GetPointer() );
  this->ProcessObject::SetNumberOfRequiredOutputs(1);
  this->ProcessObject::SetNthOutput( 0, output.GetPointer() );
}

//
// Destructor
//
template<typename TOutputVideoStream>
VideoSource<TOutputVideoStream>::~VideoSource()
{
}

//
// PrintSelf
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>
::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
}

//-PUBLIC METHODS--------------------------------------------------------------

//
// GetOutput()
//
template<typename TOutputVideoStream>
typename VideoSource< TOutputVideoStream >::OutputVideoStreamType*
VideoSource<TOutputVideoStream>::GetOutput()
{
  // Make sure there is at least 1 output
  if (this->GetNumberOfOutputs() < 1)
    {
    itkWarningMacro("No outputs set");
    return ITK_NULLPTR;
    }

  // Return the output
  return this->GetOutput(0);
}

//
// GetOutput(idx)
//
template<typename TOutputVideoStream>
TOutputVideoStream*
VideoSource<TOutputVideoStream>::GetOutput(unsigned int idx)
{
  OutputVideoStreamType* out = dynamic_cast< OutputVideoStreamType* >
    (this->TemporalProcessObject::GetOutput(idx) );

  // Make sure there is at least 1 output
  if (out == ITK_NULLPTR)
    {
    itkWarningMacro("dynamic_cast to output type failed");
    }

  return out;
}

//
// GraftOutput
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::GraftOutput(TOutputVideoStream* graft)
{
  this->GraftNthOutput(0, graft);
}

//
// GraftNthOutput
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::
GraftNthOutput(unsigned int idx, TOutputVideoStream* graft)
{
  if (idx >= this->GetNumberOfOutputs() )
    {
    itkExceptionMacro(<< "Requested to graft output " << idx
                      << " but this VideoSource only has "
                      << this->GetNumberOfOutputs() << " Outputs.");
    }
  if (!graft)
    {
    itkExceptionMacro("Cannot graft from a ITK_NULLPTR pointer");
    }

  // we use the process object method since all our outputs may not be of the
  // same type
  DataObject* output = this->ProcessObject::GetOutput(idx);
  output->Graft(graft);
}

//
// MakeOutput
//
template<typename TOutputVideoStream>
DataObject::Pointer
VideoSource<TOutputVideoStream>::MakeOutput(DataObjectPointerArraySizeType itkNotUsed(idx) )
{
  return OutputVideoStreamType::New().GetPointer();
}

//-PROTECTED METHODS-----------------------------------------------------------

//
// GenerateOutputRequestedTemporalRegion
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::
GenerateOutputRequestedTemporalRegion(TemporalDataObject* output)
{
  // Check if requested temporal region unset
  bool           resetNumFrames = false;
  TemporalRegion outputRequest = output->GetRequestedTemporalRegion();

  if (!outputRequest.GetFrameDuration() )
    {
    resetNumFrames = true;
    }

  // Call superclass's version - this will set the requested temporal region
  Superclass::GenerateOutputRequestedTemporalRegion(this->GetOutput() );

  // Make sure the output has enough buffers available for the entire output
  // only if this request has just been matched to the largest possible spatial
  // region. This should only happen for filters at the end of the pipeline
  // since mid-pipeline filters will have their outputs' requested temporal
  // regions set automatically.
  SizeValueType requestDuration =
    this->GetOutput()->GetRequestedTemporalRegion().GetFrameDuration();
  if (resetNumFrames && this->GetOutput()->GetNumberOfBuffers() < requestDuration)
    {
    this->GetOutput()->SetNumberOfBuffers(requestDuration);
    }

  // If requested temporal region was just set to largest possible, set the
  // spatial regions for every frame to the largest possible as well
  if (resetNumFrames)
    {
    SizeValueType frameStart =
      this->GetOutput()->GetRequestedTemporalRegion().GetFrameStart();
    SizeValueType numFrames =
      this->GetOutput()->GetRequestedTemporalRegion().GetFrameDuration();
    for (SizeValueType i = frameStart; i < frameStart + numFrames; ++i)
      {
      //this->GetOutput()->SetFrameRequestedSpatialRegion(i,
      //  this->GetOutput()->GetFrameLargestPossibleSpatialRegion(i));
      OutputVideoStreamType* out = this->GetOutput();
      out->GetFrameLargestPossibleSpatialRegion(i);
      }
    }
}

//
// AllocateOutputs
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::AllocateOutputs()
{
  // Get the output
  OutputVideoStreamType* output = this->GetOutput();

  // Get a list of unbuffered requested frames
  TemporalRegion unbufferedRegion = output->GetUnbufferedRequestedTemporalRegion();

  // We don't touch the buffered temporal region here because that is handled
  // by the default implementation of GenerateData in TemporalProcessObject

  // If there are no unbuffered frames, return now
  SizeValueType numFrames = unbufferedRegion.GetFrameDuration();

  if (numFrames == 0)
    {
    return;
    }

  // Initialize any empty frames (which will set region values from cache)
  output->InitializeEmptyFrames();

  // Loop through the unbuffered frames and set the buffered spatial region to
  // match the requested spatial region then allocate the data
  SizeValueType startFrame = unbufferedRegion.GetFrameStart();
  for (SizeValueType i = startFrame; i < startFrame + numFrames; ++i)
    {
    output->SetFrameBufferedSpatialRegion(i, output->GetFrameRequestedSpatialRegion(i) );
    typename OutputFrameType::Pointer frame = output->GetFrame(i);
    frame->SetBufferedRegion(output->GetFrameRequestedSpatialRegion(i) );
    frame->Allocate();
    }
}

//
// TemporalStreamingGenerateData
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::
TemporalStreamingGenerateData()
{
  // Call a method that can be overriden by a subclass to allocate
  // memory for the filter's outputs
  this->AllocateOutputs();

  // Call a method that can be overridden by a subclass to perform
  // some calculations prior to splitting the main computations into
  // separate threads
  this->BeforeThreadedGenerateData();

  // Set up the multithreaded processing
  ThreadStruct str;
  str.Filter = this;

  this->GetMultiThreader()->SetNumberOfThreads( this->GetNumberOfThreads() );
  this->GetMultiThreader()->SetSingleMethod(this->ThreaderCallback, &str);

  // multithread the execution
  this->GetMultiThreader()->SingleMethodExecute();

  // Call a method that can be overridden by a subclass to perform
  // some calculations after all the threads have completed
  this->AfterThreadedGenerateData();
}

//
// ThreadedGenerateData
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::
ThreadedGenerateData(
  const typename TOutputVideoStream::SpatialRegionType& itkNotUsed(outputRegionForThread),
  int itkNotUsed(threadId) )
{
  itkExceptionMacro( << "itk::ERROR: " << this->GetNameOfClass()
                     << "(" << this << "): "
                     << "Subclass should override this method!!!");
}

//
// SplitRequestedSpatialRegion -- Copied mostly from ImageSource
//
// Note: This implementation bases the spatial region split on the requested
// spatial region for the current Head frame of the output. This could
// potentially cause issues if frames are different sized.
//
template<typename TOutputVideoStream>
int
VideoSource<TOutputVideoStream>::
SplitRequestedSpatialRegion(int i, int num,
                            typename TOutputVideoStream::SpatialRegionType& splitRegion)
{
  // Get the output pointer and a pointer to the first output frame
  OutputVideoStreamType* outputPtr = this->GetOutput();
  SizeValueType          currentFrame = outputPtr->GetRequestedTemporalRegion().GetFrameStart();
  OutputFrameType*       framePtr = outputPtr->GetFrame(currentFrame);

  const typename TOutputVideoStream::SizeType & requestedRegionSize =
    framePtr->GetRequestedRegion().GetSize();

  int splitAxis;
  typename TOutputVideoStream::IndexType splitIndex;
  typename TOutputVideoStream::SizeType splitSize;

  // Initialize the splitRegion to the output requested region
  splitRegion = framePtr->GetRequestedRegion();
  splitIndex = splitRegion.GetIndex();
  splitSize = splitRegion.GetSize();

  // split on the outermost dimension available
  splitAxis = framePtr->GetImageDimension() - 1;
  while ( requestedRegionSize[splitAxis] == 1 )
    {
    --splitAxis;
    if ( splitAxis < 0 )
      { // cannot split
      itkDebugMacro("  Cannot Split");
      return 1;
      }
    }

  // determine the actual number of pieces that will be generated
  typename TOutputVideoStream::SizeType::SizeValueType range = requestedRegionSize[splitAxis];
  int valuesPerThread = Math::Ceil< int >(range / (double)num);
  int maxThreadIdUsed = Math::Ceil< int >(range / (double)valuesPerThread) - 1;

  // Split the region
  if ( i < maxThreadIdUsed )
    {
    splitIndex[splitAxis] += i * valuesPerThread;
    splitSize[splitAxis] = valuesPerThread;
    }
  if ( i == maxThreadIdUsed )
    {
    splitIndex[splitAxis] += i * valuesPerThread;
    // last thread needs to process the "rest" dimension being split
    splitSize[splitAxis] = splitSize[splitAxis] - i * valuesPerThread;
    }

  // set the split region ivars
  splitRegion.SetIndex(splitIndex);
  splitRegion.SetSize(splitSize);

  itkDebugMacro("  Split Piece: " << splitRegion);

  return maxThreadIdUsed + 1;
}

//
// ThreaderCallback -- Copied from ImageSource
//
template<typename TOutputVideoStream>
ITK_THREAD_RETURN_TYPE
VideoSource<TOutputVideoStream>::
ThreaderCallback(void* arg)
{
  ThreadStruct *str;
  int           total, threadId, threadCount;

  threadId = ( (MultiThreader::ThreadInfoStruct *)( arg ) )->ThreadID;
  threadCount = ( (MultiThreader::ThreadInfoStruct *)( arg ) )->NumberOfThreads;

  str = (ThreadStruct *)( ( (MultiThreader::ThreadInfoStruct *)( arg ) )->UserData );

  // execute the actual method with appropriate output region
  // first find out how many pieces extent can be split into.
  typename TOutputVideoStream::SpatialRegionType splitRegion;
  total = str->Filter->SplitRequestedSpatialRegion(threadId, threadCount, splitRegion);

  if ( threadId < total )
    {
    str->Filter->ThreadedGenerateData(splitRegion, threadId);
    }
  // else
  //   {
  //   otherwise don't use this thread. Sometimes the threads dont
  //   break up very well and it is just as efficient to leave a
  //   few threads idle.
  //   }

  return ITK_THREAD_RETURN_VALUE;
}

} // end namespace itk

#endif
<commit_msg>BUG: Fixed the runtime crash of VideoSourceTest on OSX 10.6<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed 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.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef itkVideoSource_hxx
#define itkVideoSource_hxx

#include "itkVideoSource.h"

namespace itk
{

//-CONSTRUCTOR PRINT-----------------------------------------------------------

//
// Constructor
//
template<typename TOutputVideoStream>
VideoSource<TOutputVideoStream>::VideoSource()
{
  typename OutputVideoStreamType::Pointer output =
    static_cast< OutputVideoStreamType* >( this->MakeOutput(0).GetPointer() );
  this->ProcessObject::SetNumberOfRequiredOutputs(1);
  this->ProcessObject::SetNthOutput( 0, output.GetPointer() );
}

//
// Destructor
//
template<typename TOutputVideoStream>
VideoSource<TOutputVideoStream>::~VideoSource()
{
}

//
// PrintSelf
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>
::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
}

//-PUBLIC METHODS--------------------------------------------------------------

//
// GetOutput()
//
template<typename TOutputVideoStream>
typename VideoSource< TOutputVideoStream >::OutputVideoStreamType*
VideoSource<TOutputVideoStream>::GetOutput()
{
  // Make sure there is at least 1 output
  if (this->GetNumberOfOutputs() < 1)
    {
    itkWarningMacro("No outputs set");
    return ITK_NULLPTR;
    }

  // Return the output
  return this->GetOutput(0);
}

//
// GetOutput(idx)
//
template<typename TOutputVideoStream>
TOutputVideoStream*
VideoSource<TOutputVideoStream>::GetOutput(unsigned int idx)
{
  OutputVideoStreamType* out = dynamic_cast< OutputVideoStreamType* >
    (this->TemporalProcessObject::GetOutput(idx) );

  // Make sure there is at least 1 output
  if (out == ITK_NULLPTR)
    {
    itkWarningMacro("dynamic_cast to output type failed");
    }

  return out;
}

//
// GraftOutput
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::GraftOutput(TOutputVideoStream* graft)
{
  this->GraftNthOutput(0, graft);
}

//
// GraftNthOutput
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::
GraftNthOutput(unsigned int idx, TOutputVideoStream* graft)
{
  if (idx >= this->GetNumberOfOutputs() )
    {
    itkExceptionMacro(<< "Requested to graft output " << idx
                      << " but this VideoSource only has "
                      << this->GetNumberOfOutputs() << " Outputs.");
    }
  if (!graft)
    {
    itkExceptionMacro("Cannot graft from a ITK_NULLPTR pointer");
    }

  // we use the process object method since all our outputs may not be of the
  // same type
  DataObject* output = this->ProcessObject::GetOutput(idx);
  output->Graft(graft);
}

//
// MakeOutput
//
template<typename TOutputVideoStream>
DataObject::Pointer
VideoSource<TOutputVideoStream>::MakeOutput(DataObjectPointerArraySizeType itkNotUsed(idx) )
{
  return OutputVideoStreamType::New().GetPointer();
}

//-PROTECTED METHODS-----------------------------------------------------------

//
// GenerateOutputRequestedTemporalRegion
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::
GenerateOutputRequestedTemporalRegion(TemporalDataObject* output)
{
  // Check if requested temporal region unset
  bool           resetNumFrames = false;
  TemporalRegion outputRequest = output->GetRequestedTemporalRegion();

  if (!outputRequest.GetFrameDuration() )
    {
    resetNumFrames = true;
    }

  // Call superclass's version - this will set the requested temporal region
  Superclass::GenerateOutputRequestedTemporalRegion(this->GetOutput() );

  // Make sure the output has enough buffers available for the entire output
  // only if this request has just been matched to the largest possible spatial
  // region. This should only happen for filters at the end of the pipeline
  // since mid-pipeline filters will have their outputs' requested temporal
  // regions set automatically.
  SizeValueType requestDuration =
    this->GetOutput()->GetRequestedTemporalRegion().GetFrameDuration();
  if (resetNumFrames && this->GetOutput()->GetNumberOfBuffers() < requestDuration)
    {
    this->GetOutput()->SetNumberOfBuffers(requestDuration);
    }

  // If requested temporal region was just set to largest possible, set the
  // spatial regions for every frame to the largest possible as well
  if (resetNumFrames)
    {
    SizeValueType frameStart =
      this->GetOutput()->GetRequestedTemporalRegion().GetFrameStart();
    SizeValueType numFrames =
      this->GetOutput()->GetRequestedTemporalRegion().GetFrameDuration();
    for (SizeValueType i = frameStart; i < frameStart + numFrames; ++i)
      {
      //this->GetOutput()->SetFrameRequestedSpatialRegion(i,
      //  this->GetOutput()->GetFrameLargestPossibleSpatialRegion(i));
      OutputVideoStreamType* out = this->GetOutput();
      out->GetFrameLargestPossibleSpatialRegion(i);
      }
    }
}

//
// AllocateOutputs
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::AllocateOutputs()
{
  // Get the output
  OutputVideoStreamType* output = this->GetOutput();

  // Get a list of unbuffered requested frames
  TemporalRegion unbufferedRegion = output->GetUnbufferedRequestedTemporalRegion();

  // We don't touch the buffered temporal region here because that is handled
  // by the default implementation of GenerateData in TemporalProcessObject

  // If there are no unbuffered frames, return now
  SizeValueType numFrames = unbufferedRegion.GetFrameDuration();

  if (numFrames == 0)
    {
    return;
    }

  // Initialize any empty frames (which will set region values from cache)
  output->InitializeEmptyFrames();

  // Loop through the unbuffered frames and set the buffered spatial region to
  // match the requested spatial region then allocate the data
  SizeValueType startFrame = unbufferedRegion.GetFrameStart();
  for (SizeValueType i = startFrame; i < startFrame + numFrames; ++i)
    {
    output->SetFrameBufferedSpatialRegion(i, output->GetFrameRequestedSpatialRegion(i) );
    typename OutputFrameType::Pointer frame = output->GetFrame(i);
    frame->SetBufferedRegion(output->GetFrameRequestedSpatialRegion(i) );
    frame->Allocate();
    }
}

//
// TemporalStreamingGenerateData
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::
TemporalStreamingGenerateData()
{
  // Call a method that can be overriden by a subclass to allocate
  // memory for the filter's outputs
  this->AllocateOutputs();

  // Call a method that can be overridden by a subclass to perform
  // some calculations prior to splitting the main computations into
  // separate threads
  this->BeforeThreadedGenerateData();

  // Set up the multithreaded processing
  ThreadStruct str;
  str.Filter = this;

  this->GetMultiThreader()->SetNumberOfThreads( this->GetNumberOfThreads() );
  this->GetMultiThreader()->SetSingleMethod(this->ThreaderCallback, &str);

  // multithread the execution
  this->GetMultiThreader()->SingleMethodExecute();

  // Call a method that can be overridden by a subclass to perform
  // some calculations after all the threads have completed
  this->AfterThreadedGenerateData();
}

//
// ThreadedGenerateData
//
template<typename TOutputVideoStream>
void
VideoSource<TOutputVideoStream>::
ThreadedGenerateData(
  const typename TOutputVideoStream::SpatialRegionType& itkNotUsed(outputRegionForThread),
  int itkNotUsed(threadId) )
{
  itkExceptionMacro( << "itk::ERROR: " << this->GetNameOfClass()
                     << "(" << this << "): "
                     << "Subclass should override this method!!!");
}

//
// SplitRequestedSpatialRegion -- Copied mostly from ImageSource
//
// Note: This implementation bases the spatial region split on the requested
// spatial region for the current Head frame of the output. This could
// potentially cause issues if frames are different sized.
//
template<typename TOutputVideoStream>
int
VideoSource<TOutputVideoStream>::
SplitRequestedSpatialRegion(int i, int num,
                            typename TOutputVideoStream::SpatialRegionType& splitRegion)
{
  // Get the output pointer and a pointer to the first output frame
  OutputVideoStreamType* outputPtr = this->GetOutput();
  SizeValueType          currentFrame = outputPtr->GetRequestedTemporalRegion().GetFrameStart();
  OutputFrameType*       framePtr = outputPtr->GetFrame(currentFrame);

  const typename TOutputVideoStream::SizeType & requestedRegionSize =
    framePtr->GetRequestedRegion().GetSize();

  int splitAxis;
  typename TOutputVideoStream::IndexType splitIndex;
  typename TOutputVideoStream::SizeType splitSize;

  // Initialize the splitRegion to the output requested region
  splitRegion = framePtr->GetRequestedRegion();
  splitIndex = splitRegion.GetIndex();
  splitSize = splitRegion.GetSize();

  // split on the outermost dimension available
  splitAxis = framePtr->GetImageDimension() - 1;
  while ( requestedRegionSize[splitAxis] == 1 )
    {
    --splitAxis;
    if ( splitAxis < 0 )
      { // cannot split
      itkDebugMacro("  Cannot Split");
      return 1;
      }
    }

  // determine the actual number of pieces that will be generated
  typename TOutputVideoStream::SizeType::SizeValueType range = requestedRegionSize[splitAxis];

  int valuesPerThread;
  int maxThreadIdUsed;
  if (range == 0)
    {
    valuesPerThread = 0;
    maxThreadIdUsed = 0;
    }
  else
    {
    valuesPerThread = Math::Ceil< int >(range / (double)num);
    maxThreadIdUsed = Math::Ceil< int >(range / (double)valuesPerThread) - 1;
    }

  // Split the region
  if ( i < maxThreadIdUsed )
    {
    splitIndex[splitAxis] += i * valuesPerThread;
    splitSize[splitAxis] = valuesPerThread;
    }
  if ( i == maxThreadIdUsed )
    {
    splitIndex[splitAxis] += i * valuesPerThread;
    // last thread needs to process the "rest" dimension being split
    splitSize[splitAxis] = splitSize[splitAxis] - i * valuesPerThread;
    }

  // set the split region ivars
  splitRegion.SetIndex(splitIndex);
  splitRegion.SetSize(splitSize);

  itkDebugMacro("  Split Piece: " << splitRegion);

  return maxThreadIdUsed + 1;
}

//
// ThreaderCallback -- Copied from ImageSource
//
template<typename TOutputVideoStream>
ITK_THREAD_RETURN_TYPE
VideoSource<TOutputVideoStream>::
ThreaderCallback(void* arg)
{
  ThreadStruct *str;
  int           total, threadId, threadCount;

  threadId = ( (MultiThreader::ThreadInfoStruct *)( arg ) )->ThreadID;
  threadCount = ( (MultiThreader::ThreadInfoStruct *)( arg ) )->NumberOfThreads;

  str = (ThreadStruct *)( ( (MultiThreader::ThreadInfoStruct *)( arg ) )->UserData );

  // execute the actual method with appropriate output region
  // first find out how many pieces extent can be split into.
  typename TOutputVideoStream::SpatialRegionType splitRegion;
  total = str->Filter->SplitRequestedSpatialRegion(threadId, threadCount, splitRegion);

  if ( threadId < total )
    {
    str->Filter->ThreadedGenerateData(splitRegion, threadId);
    }
  // else
  //   {
  //   otherwise don't use this thread. Sometimes the threads dont
  //   break up very well and it is just as efficient to leave a
  //   few threads idle.
  //   }

  return ITK_THREAD_RETURN_VALUE;
}

} // end namespace itk

#endif
<|endoftext|>


<commit_before>// Copyright 2013 The Flutter 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/shell/platform/linux/public/flutter_linux/fl_method_call.h"
#include "flutter/shell/platform/linux/fl_method_call_private.h"
#include "flutter/shell/platform/linux/fl_method_channel_private.h"

#include <gmodule.h>

struct _FlMethodCall {
  GObject parent_instance;

  // Name of method being called.
  gchar* name;

  // Arguments provided to method call.
  FlValue* args;

  // Channel to respond on.
  FlMethodChannel* channel;
  FlBinaryMessengerResponseHandle* response_handle;
};

G_DEFINE_TYPE(FlMethodCall, fl_method_call, G_TYPE_OBJECT)

static void fl_method_call_dispose(GObject* object) {
  FlMethodCall* self = FL_METHOD_CALL(object);

  g_clear_pointer(&self->name, g_free);
  g_clear_pointer(&self->args, fl_value_unref);
  g_clear_object(&self->channel);
  g_clear_object(&self->response_handle);

  G_OBJECT_CLASS(fl_method_call_parent_class)->dispose(object);
}

static void fl_method_call_class_init(FlMethodCallClass* klass) {
  G_OBJECT_CLASS(klass)->dispose = fl_method_call_dispose;
}

static void fl_method_call_init(FlMethodCall* self) {}

FlMethodCall* fl_method_call_new(
    const gchar* name,
    FlValue* args,
    FlMethodChannel* channel,
    FlBinaryMessengerResponseHandle* response_handle) {
  g_return_val_if_fail(name != nullptr, nullptr);
  g_return_val_if_fail(args != nullptr, nullptr);
  g_return_val_if_fail(FL_IS_METHOD_CHANNEL(channel), nullptr);
  g_return_val_if_fail(FL_IS_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle),
                       nullptr);

  FlMethodCall* self =
      FL_METHOD_CALL(g_object_new(fl_method_call_get_type(), nullptr));

  self->name = g_strdup(name);
  self->args = fl_value_ref(args);
  self->channel = FL_METHOD_CHANNEL(g_object_ref(channel));
  self->response_handle =
      FL_BINARY_MESSENGER_RESPONSE_HANDLE(g_object_ref(response_handle));

  return self;
}

G_MODULE_EXPORT const gchar* fl_method_call_get_name(FlMethodCall* self) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), nullptr);
  return self->name;
}

G_MODULE_EXPORT FlValue* fl_method_call_get_args(FlMethodCall* self) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), nullptr);
  return self->args;
}

G_MODULE_EXPORT gboolean fl_method_call_respond(FlMethodCall* self,
                                                FlMethodResponse* response,
                                                GError** error) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), FALSE);
  g_return_val_if_fail(FL_IS_METHOD_RESPONSE(response), FALSE);
  return fl_method_channel_respond(self->channel, self->response_handle,
                                   response, error);
}

G_MODULE_EXPORT gboolean fl_method_call_respond_success(FlMethodCall* self,
                                                        FlValue* result,
                                                        GError** error) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), FALSE);

  g_autoptr(FlMethodResponse) response =
      FL_METHOD_RESPONSE(fl_method_success_response_new(result));
  return fl_method_channel_respond(self->channel, self->response_handle,
                                   response, error);
}

G_MODULE_EXPORT gboolean fl_method_call_respond_error(FlMethodCall* self,
                                                      const gchar* code,
                                                      const gchar* message,
                                                      FlValue* details,
                                                      GError** error) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), FALSE);
  g_return_val_if_fail(code != nullptr, FALSE);

  g_autoptr(FlMethodResponse) response =
      FL_METHOD_RESPONSE(fl_method_error_response_new(code, message, details));
  return fl_method_channel_respond(self->channel, self->response_handle,
                                   response, error);
}

G_MODULE_EXPORT gboolean
fl_method_call_respond_not_implemented(FlMethodCall* self, GError** error) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), FALSE);

  g_autoptr(FlMethodResponse) response =
      FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
  return fl_method_channel_respond(self->channel, self->response_handle,
                                   response, error);
}
<commit_msg>Show warning if method response errors occur and error not handled. (#18946)<commit_after>// Copyright 2013 The Flutter 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/shell/platform/linux/public/flutter_linux/fl_method_call.h"
#include "flutter/shell/platform/linux/fl_method_call_private.h"
#include "flutter/shell/platform/linux/fl_method_channel_private.h"

#include <gmodule.h>

struct _FlMethodCall {
  GObject parent_instance;

  // Name of method being called.
  gchar* name;

  // Arguments provided to method call.
  FlValue* args;

  // Channel to respond on.
  FlMethodChannel* channel;
  FlBinaryMessengerResponseHandle* response_handle;
};

G_DEFINE_TYPE(FlMethodCall, fl_method_call, G_TYPE_OBJECT)

static void fl_method_call_dispose(GObject* object) {
  FlMethodCall* self = FL_METHOD_CALL(object);

  g_clear_pointer(&self->name, g_free);
  g_clear_pointer(&self->args, fl_value_unref);
  g_clear_object(&self->channel);
  g_clear_object(&self->response_handle);

  G_OBJECT_CLASS(fl_method_call_parent_class)->dispose(object);
}

static void fl_method_call_class_init(FlMethodCallClass* klass) {
  G_OBJECT_CLASS(klass)->dispose = fl_method_call_dispose;
}

static void fl_method_call_init(FlMethodCall* self) {}

FlMethodCall* fl_method_call_new(
    const gchar* name,
    FlValue* args,
    FlMethodChannel* channel,
    FlBinaryMessengerResponseHandle* response_handle) {
  g_return_val_if_fail(name != nullptr, nullptr);
  g_return_val_if_fail(args != nullptr, nullptr);
  g_return_val_if_fail(FL_IS_METHOD_CHANNEL(channel), nullptr);
  g_return_val_if_fail(FL_IS_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle),
                       nullptr);

  FlMethodCall* self =
      FL_METHOD_CALL(g_object_new(fl_method_call_get_type(), nullptr));

  self->name = g_strdup(name);
  self->args = fl_value_ref(args);
  self->channel = FL_METHOD_CHANNEL(g_object_ref(channel));
  self->response_handle =
      FL_BINARY_MESSENGER_RESPONSE_HANDLE(g_object_ref(response_handle));

  return self;
}

G_MODULE_EXPORT const gchar* fl_method_call_get_name(FlMethodCall* self) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), nullptr);
  return self->name;
}

G_MODULE_EXPORT FlValue* fl_method_call_get_args(FlMethodCall* self) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), nullptr);
  return self->args;
}

G_MODULE_EXPORT gboolean fl_method_call_respond(FlMethodCall* self,
                                                FlMethodResponse* response,
                                                GError** error) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), FALSE);
  g_return_val_if_fail(FL_IS_METHOD_RESPONSE(response), FALSE);

  g_autoptr(GError) local_error = nullptr;
  if (!fl_method_channel_respond(self->channel, self->response_handle, response,
                                 &local_error)) {
    // If the developer chose not to handle the error then log it so it's not
    // missed.
    if (error == nullptr) {
      g_warning("Failed to send method call response: %s",
                local_error->message);
    }

    g_propagate_error(error, local_error);
    return FALSE;
  }

  return TRUE;
}

G_MODULE_EXPORT gboolean fl_method_call_respond_success(FlMethodCall* self,
                                                        FlValue* result,
                                                        GError** error) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), FALSE);

  g_autoptr(FlMethodResponse) response =
      FL_METHOD_RESPONSE(fl_method_success_response_new(result));
  return fl_method_channel_respond(self->channel, self->response_handle,
                                   response, error);
}

G_MODULE_EXPORT gboolean fl_method_call_respond_error(FlMethodCall* self,
                                                      const gchar* code,
                                                      const gchar* message,
                                                      FlValue* details,
                                                      GError** error) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), FALSE);
  g_return_val_if_fail(code != nullptr, FALSE);

  g_autoptr(FlMethodResponse) response =
      FL_METHOD_RESPONSE(fl_method_error_response_new(code, message, details));
  return fl_method_channel_respond(self->channel, self->response_handle,
                                   response, error);
}

G_MODULE_EXPORT gboolean
fl_method_call_respond_not_implemented(FlMethodCall* self, GError** error) {
  g_return_val_if_fail(FL_IS_METHOD_CALL(self), FALSE);

  g_autoptr(FlMethodResponse) response =
      FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
  return fl_method_channel_respond(self->channel, self->response_handle,
                                   response, error);
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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.

// This file contains definitions for CppBoundClass

// Here's the control flow of a JS method getting forwarded to a class.
// - Something calls our NPObject with a function like "Invoke".
// - CppNPObject's static invoke() function forwards it to its attached
//   CppBoundClass's Invoke() method.
// - CppBoundClass has then overridden Invoke() to look up the function
//   name in its internal map of methods, and then calls the appropriate
//   method.

#include "config.h"

#include "webkit/glue/cpp_bound_class.h"
#include "webkit/glue/webframe.h"

// This is required for the KJS build due to an artifact of the
// npruntime_priv.h file from JavaScriptCore/bindings.
#pragma warning(disable:4067)
#include "npruntime_priv.h"

#if USE(JSC)
#pragma warning(push, 0)
#include "JSLock.h"
#pragma warning(pop)
#endif

// Our special NPObject type.  We extend an NPObject with a pointer to a
// CppBoundClass, which is just a C++ interface that we forward all NPObject
// callbacks to.
struct CppNPObject {
  NPObject parent;  // This must be the first field in the struct.
  CppBoundClass* bound_class;

  //
  // All following objects and functions are static, and just used to interface
  // with NPObject/NPClass.
  //

  // An NPClass associates static functions of CppNPObject with the
  // function pointers used by the JS runtime.
  static NPClass np_class_;

  // Allocate a new NPObject with the specified class.
  static NPObject* allocate(NPP npp, NPClass* aClass);

  // Free an object.
  static void deallocate(NPObject* obj);

  // Returns true if the C++ class associated with this NPObject exposes the
  // given property.  Called by the JS runtime.
  static bool hasProperty(NPObject *obj, NPIdentifier ident);

  // Returns true if the C++ class associated with this NPObject exposes the
  // given method.  Called by the JS runtime.
  static bool hasMethod(NPObject *obj, NPIdentifier ident);

  // If the given method is exposed by the C++ class associated with this
  // NPObject, invokes it with the given args and returns a result.  Otherwise,
  // returns "undefined" (in the JavaScript sense).  Called by the JS runtime.
  static bool invoke(NPObject *obj, NPIdentifier ident,
                     const NPVariant *args, uint32_t arg_count,
                     NPVariant *result);

  // If the given property is exposed by the C++ class associated with this
  // NPObject, returns its value.  Otherwise, returns "undefined" (in the
  // JavaScript sense).  Called by the JS runtime.
  static bool getProperty(NPObject *obj, NPIdentifier ident,
                          NPVariant *result);

  // If the given property is exposed by the C++ class associated with this
  // NPObject, sets its value.  Otherwise, does nothing. Called by the JS
  // runtime.
  static bool setProperty(NPObject *obj, NPIdentifier ident,
                          const NPVariant *value);
};

// Build CppNPObject's static function pointers into an NPClass, for use
// in constructing NPObjects for the C++ classes.
NPClass CppNPObject::np_class_ = {
  NP_CLASS_STRUCT_VERSION,
  CppNPObject::allocate,
  CppNPObject::deallocate,
  /* NPInvalidateFunctionPtr */ NULL,
  CppNPObject::hasMethod,
  CppNPObject::invoke,
  /* NPInvokeDefaultFunctionPtr */ NULL,
  CppNPObject::hasProperty,
  CppNPObject::getProperty,
  CppNPObject::setProperty,
  /* NPRemovePropertyFunctionPtr */ NULL
};

/* static */ NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass) {
  CppNPObject* obj = new CppNPObject;
  // obj->parent will be initialized by the NPObject code calling this.
  obj->bound_class = NULL;
  return &obj->parent;
}

/* static */ void CppNPObject::deallocate(NPObject* np_obj) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  delete obj;
}

/* static */ bool CppNPObject::hasMethod(NPObject* np_obj,
                                         NPIdentifier ident) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  return obj->bound_class->HasMethod(ident);
}

/* static */ bool CppNPObject::hasProperty(NPObject* np_obj,
                                           NPIdentifier ident) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  return obj->bound_class->HasProperty(ident);
}

/* static */ bool CppNPObject::invoke(NPObject* np_obj, NPIdentifier ident,
                                      const NPVariant* args, uint32_t arg_count,
                                      NPVariant* result) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  return obj->bound_class->Invoke(ident, args, arg_count, result);
}

/* static */ bool CppNPObject::getProperty(NPObject* np_obj,
                                           NPIdentifier ident,
                                           NPVariant* result) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  return obj->bound_class->GetProperty(ident, result);
}

/* static */ bool CppNPObject::setProperty(NPObject* np_obj,
                                           NPIdentifier ident,
                                           const NPVariant* value) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  return obj->bound_class->SetProperty(ident, value);
}

CppBoundClass::~CppBoundClass() {
  for (MethodList::iterator i = methods_.begin(); i != methods_.end(); ++i)
    delete i->second;

  // Unregister objects we created and bound to a frame.
  for (BoundObjectList::iterator i = bound_objects_.begin();
      i != bound_objects_.end(); ++i) {
#if USE(V8)
    _NPN_UnregisterObject(*i);
#endif
    NPN_ReleaseObject(*i);
  }
}

bool CppBoundClass::HasMethod(NPIdentifier ident) {
  return (methods_.find(ident) != methods_.end());
}

bool CppBoundClass::HasProperty(NPIdentifier ident) {
  return (properties_.find(ident) != properties_.end());
}

bool CppBoundClass::Invoke(NPIdentifier ident,
                              const NPVariant* args,
                              size_t arg_count,
                              NPVariant* result) {
  MethodList::const_iterator method = methods_.find(ident);
  Callback* callback;
  if (method == methods_.end()) {
    if (fallback_callback_.get()) {
      callback = fallback_callback_.get();
    } else {
      VOID_TO_NPVARIANT(*result);
      return false;
    }
  } else {
    callback = (*method).second;
  }

  // Build a CppArgumentList argument vector from the NPVariants coming in.
  CppArgumentList cpp_args(arg_count);
  for (size_t i = 0; i < arg_count; i++)
    cpp_args[i].Set(args[i]);

  CppVariant cpp_result;
  callback->Run(cpp_args, &cpp_result);

  cpp_result.CopyToNPVariant(result);
  return true;
}

bool CppBoundClass::GetProperty(NPIdentifier ident, NPVariant* result) {
  PropertyList::const_iterator prop = properties_.find(ident);
  if (prop == properties_.end()) {
    VOID_TO_NPVARIANT(*result);
    return false;
  }

  const CppVariant* cpp_value = (*prop).second;
  cpp_value->CopyToNPVariant(result);
  return true;
}

bool CppBoundClass::SetProperty(NPIdentifier ident,
                                   const NPVariant* value) {
  PropertyList::iterator prop = properties_.find(ident);
  if (prop == properties_.end())
    return false;

  (*prop).second->Set(*value);
  return true;
}

void CppBoundClass::BindCallback(std::string name, Callback* callback) {
  // NPUTF8 is a typedef for char, so this cast is safe.
  NPIdentifier ident = NPN_GetStringIdentifier((const NPUTF8*)name.c_str());
  MethodList::iterator old_callback = methods_.find(ident);
  if (old_callback != methods_.end())
    delete old_callback->second;
  methods_[ident] = callback;
}

void CppBoundClass::BindProperty(std::string name, CppVariant* prop) {
  // NPUTF8 is a typedef for char, so this cast is safe.
  NPIdentifier ident = NPN_GetStringIdentifier((const NPUTF8*)name.c_str());
  properties_[ident] = prop;
}

bool CppBoundClass::IsMethodRegistered(std::string name) {
  // NPUTF8 is a typedef for char, so this cast is safe.
  NPIdentifier ident = NPN_GetStringIdentifier((const NPUTF8*)name.c_str());
  MethodList::iterator callback = methods_.find(ident);
  return (callback != methods_.end());
}

void CppBoundClass::BindToJavascript(WebFrame* frame,
                                     const std::wstring& classname) {
#if USE(JSC)
  KJS::JSLock lock;
#endif

  // Create an NPObject using our static NPClass.  The first argument (a
  // plugin's instance handle) is passed through to the allocate function
  // directly, and we don't use it, so it's ok to be 0.
  NPObject* np_obj = NPN_CreateObject(0, &CppNPObject::np_class_);
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  obj->bound_class = this;

  // BindToWindowObject will (indirectly) retain the np_object. We save it
  // so we can release it when we're destroyed.
  frame->BindToWindowObject(classname, np_obj);
  bound_objects_.push_back(np_obj);
}

<commit_msg>KJS::Lock constructor now takes a bool. Fix 1 build error! Review URL: http://codereview.chromium.org/7020<commit_after>// Copyright (c) 2006-2008 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.

// This file contains definitions for CppBoundClass

// Here's the control flow of a JS method getting forwarded to a class.
// - Something calls our NPObject with a function like "Invoke".
// - CppNPObject's static invoke() function forwards it to its attached
//   CppBoundClass's Invoke() method.
// - CppBoundClass has then overridden Invoke() to look up the function
//   name in its internal map of methods, and then calls the appropriate
//   method.

#include "config.h"

#include "webkit/glue/cpp_bound_class.h"
#include "webkit/glue/webframe.h"

// This is required for the KJS build due to an artifact of the
// npruntime_priv.h file from JavaScriptCore/bindings.
#pragma warning(disable:4067)
#include "npruntime_priv.h"

#if USE(JSC)
#pragma warning(push, 0)
#include "JSLock.h"
#pragma warning(pop)
#endif

// Our special NPObject type.  We extend an NPObject with a pointer to a
// CppBoundClass, which is just a C++ interface that we forward all NPObject
// callbacks to.
struct CppNPObject {
  NPObject parent;  // This must be the first field in the struct.
  CppBoundClass* bound_class;

  //
  // All following objects and functions are static, and just used to interface
  // with NPObject/NPClass.
  //

  // An NPClass associates static functions of CppNPObject with the
  // function pointers used by the JS runtime.
  static NPClass np_class_;

  // Allocate a new NPObject with the specified class.
  static NPObject* allocate(NPP npp, NPClass* aClass);

  // Free an object.
  static void deallocate(NPObject* obj);

  // Returns true if the C++ class associated with this NPObject exposes the
  // given property.  Called by the JS runtime.
  static bool hasProperty(NPObject *obj, NPIdentifier ident);

  // Returns true if the C++ class associated with this NPObject exposes the
  // given method.  Called by the JS runtime.
  static bool hasMethod(NPObject *obj, NPIdentifier ident);

  // If the given method is exposed by the C++ class associated with this
  // NPObject, invokes it with the given args and returns a result.  Otherwise,
  // returns "undefined" (in the JavaScript sense).  Called by the JS runtime.
  static bool invoke(NPObject *obj, NPIdentifier ident,
                     const NPVariant *args, uint32_t arg_count,
                     NPVariant *result);

  // If the given property is exposed by the C++ class associated with this
  // NPObject, returns its value.  Otherwise, returns "undefined" (in the
  // JavaScript sense).  Called by the JS runtime.
  static bool getProperty(NPObject *obj, NPIdentifier ident,
                          NPVariant *result);

  // If the given property is exposed by the C++ class associated with this
  // NPObject, sets its value.  Otherwise, does nothing. Called by the JS
  // runtime.
  static bool setProperty(NPObject *obj, NPIdentifier ident,
                          const NPVariant *value);
};

// Build CppNPObject's static function pointers into an NPClass, for use
// in constructing NPObjects for the C++ classes.
NPClass CppNPObject::np_class_ = {
  NP_CLASS_STRUCT_VERSION,
  CppNPObject::allocate,
  CppNPObject::deallocate,
  /* NPInvalidateFunctionPtr */ NULL,
  CppNPObject::hasMethod,
  CppNPObject::invoke,
  /* NPInvokeDefaultFunctionPtr */ NULL,
  CppNPObject::hasProperty,
  CppNPObject::getProperty,
  CppNPObject::setProperty,
  /* NPRemovePropertyFunctionPtr */ NULL
};

/* static */ NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass) {
  CppNPObject* obj = new CppNPObject;
  // obj->parent will be initialized by the NPObject code calling this.
  obj->bound_class = NULL;
  return &obj->parent;
}

/* static */ void CppNPObject::deallocate(NPObject* np_obj) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  delete obj;
}

/* static */ bool CppNPObject::hasMethod(NPObject* np_obj,
                                         NPIdentifier ident) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  return obj->bound_class->HasMethod(ident);
}

/* static */ bool CppNPObject::hasProperty(NPObject* np_obj,
                                           NPIdentifier ident) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  return obj->bound_class->HasProperty(ident);
}

/* static */ bool CppNPObject::invoke(NPObject* np_obj, NPIdentifier ident,
                                      const NPVariant* args, uint32_t arg_count,
                                      NPVariant* result) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  return obj->bound_class->Invoke(ident, args, arg_count, result);
}

/* static */ bool CppNPObject::getProperty(NPObject* np_obj,
                                           NPIdentifier ident,
                                           NPVariant* result) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  return obj->bound_class->GetProperty(ident, result);
}

/* static */ bool CppNPObject::setProperty(NPObject* np_obj,
                                           NPIdentifier ident,
                                           const NPVariant* value) {
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  return obj->bound_class->SetProperty(ident, value);
}

CppBoundClass::~CppBoundClass() {
  for (MethodList::iterator i = methods_.begin(); i != methods_.end(); ++i)
    delete i->second;

  // Unregister objects we created and bound to a frame.
  for (BoundObjectList::iterator i = bound_objects_.begin();
      i != bound_objects_.end(); ++i) {
#if USE(V8)
    _NPN_UnregisterObject(*i);
#endif
    NPN_ReleaseObject(*i);
  }
}

bool CppBoundClass::HasMethod(NPIdentifier ident) {
  return (methods_.find(ident) != methods_.end());
}

bool CppBoundClass::HasProperty(NPIdentifier ident) {
  return (properties_.find(ident) != properties_.end());
}

bool CppBoundClass::Invoke(NPIdentifier ident,
                              const NPVariant* args,
                              size_t arg_count,
                              NPVariant* result) {
  MethodList::const_iterator method = methods_.find(ident);
  Callback* callback;
  if (method == methods_.end()) {
    if (fallback_callback_.get()) {
      callback = fallback_callback_.get();
    } else {
      VOID_TO_NPVARIANT(*result);
      return false;
    }
  } else {
    callback = (*method).second;
  }

  // Build a CppArgumentList argument vector from the NPVariants coming in.
  CppArgumentList cpp_args(arg_count);
  for (size_t i = 0; i < arg_count; i++)
    cpp_args[i].Set(args[i]);

  CppVariant cpp_result;
  callback->Run(cpp_args, &cpp_result);

  cpp_result.CopyToNPVariant(result);
  return true;
}

bool CppBoundClass::GetProperty(NPIdentifier ident, NPVariant* result) {
  PropertyList::const_iterator prop = properties_.find(ident);
  if (prop == properties_.end()) {
    VOID_TO_NPVARIANT(*result);
    return false;
  }

  const CppVariant* cpp_value = (*prop).second;
  cpp_value->CopyToNPVariant(result);
  return true;
}

bool CppBoundClass::SetProperty(NPIdentifier ident,
                                   const NPVariant* value) {
  PropertyList::iterator prop = properties_.find(ident);
  if (prop == properties_.end())
    return false;

  (*prop).second->Set(*value);
  return true;
}

void CppBoundClass::BindCallback(std::string name, Callback* callback) {
  // NPUTF8 is a typedef for char, so this cast is safe.
  NPIdentifier ident = NPN_GetStringIdentifier((const NPUTF8*)name.c_str());
  MethodList::iterator old_callback = methods_.find(ident);
  if (old_callback != methods_.end())
    delete old_callback->second;
  methods_[ident] = callback;
}

void CppBoundClass::BindProperty(std::string name, CppVariant* prop) {
  // NPUTF8 is a typedef for char, so this cast is safe.
  NPIdentifier ident = NPN_GetStringIdentifier((const NPUTF8*)name.c_str());
  properties_[ident] = prop;
}

bool CppBoundClass::IsMethodRegistered(std::string name) {
  // NPUTF8 is a typedef for char, so this cast is safe.
  NPIdentifier ident = NPN_GetStringIdentifier((const NPUTF8*)name.c_str());
  MethodList::iterator callback = methods_.find(ident);
  return (callback != methods_.end());
}

void CppBoundClass::BindToJavascript(WebFrame* frame,
                                     const std::wstring& classname) {
#if USE(JSC)
  KJS::JSLock lock(false);
#endif

  // Create an NPObject using our static NPClass.  The first argument (a
  // plugin's instance handle) is passed through to the allocate function
  // directly, and we don't use it, so it's ok to be 0.
  NPObject* np_obj = NPN_CreateObject(0, &CppNPObject::np_class_);
  CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
  obj->bound_class = this;

  // BindToWindowObject will (indirectly) retain the np_object. We save it
  // so we can release it when we're destroyed.
  frame->BindToWindowObject(classname, np_obj);
  bound_objects_.push_back(np_obj);
}

<|endoftext|>