<commit_before>#include <boost/test/unit_test.hpp>

#include <index-manager/IndexManager.h>
#include <search-manager/AllDocumentIterator.h>

using namespace sf1r;
using namespace izenelib::ir::indexmanager;

BOOST_AUTO_TEST_SUITE( AllDocumentIterator_Suite )

static unsigned maxDoc = 100;

BOOST_AUTO_TEST_CASE(alldociter_test)
{
    {
        boost::shared_ptr<IndexManager::FilterBitmapT> pFilterIdSet(new IndexManager::FilterBitmapT);

        pFilterIdSet->set(1);
        pFilterIdSet->set(2);
        pFilterIdSet->set(3);
        pFilterIdSet->set(4);
        pFilterIdSet->set(5);
        pFilterIdSet->set(6);
        pFilterIdSet->set(10);
        pFilterIdSet->set(20);
        pFilterIdSet->set(30);
        pFilterIdSet->set(33);
        pFilterIdSet->set(40);
        pFilterIdSet->set(50);
        pFilterIdSet->set(100);

        IndexManager::FilterTermDocFreqsT* pFilterTermDocFreqs = new IndexManager::FilterTermDocFreqsT(pFilterIdSet);
        AllDocumentIterator* pIterator = new AllDocumentIterator(pFilterTermDocFreqs, maxDoc);

        //pIterator->next();
        unsigned doc = pIterator->skipTo(2);
        BOOST_CHECK_EQUAL(doc, 7U);
        doc = pIterator->skipTo(3);
        BOOST_CHECK_EQUAL(doc, 7U);
        doc = pIterator->skipTo(4);
        BOOST_CHECK_EQUAL(doc, 7U);
        doc = pIterator->skipTo(5);
        BOOST_CHECK_EQUAL(doc, 7);
        doc = pIterator->skipTo(6);
        BOOST_CHECK_EQUAL(doc, 7U);
        doc = pIterator->skipTo(8);
        BOOST_CHECK_EQUAL(doc, 9U);
        doc = pIterator->skipTo(9);
        BOOST_CHECK_EQUAL(doc, 11U);
        doc = pIterator->skipTo(10);
        BOOST_CHECK_EQUAL(doc, 11U);
        doc = pIterator->skipTo(20);
        BOOST_CHECK_EQUAL(doc, 21U);
        doc = pIterator->skipTo(30);
        BOOST_CHECK_EQUAL(doc, 31U);
        doc = pIterator->skipTo(40);
        BOOST_CHECK_EQUAL(doc, 41U);
        doc = pIterator->skipTo(50);
        BOOST_CHECK_EQUAL(doc, 51U);
        doc = pIterator->skipTo(60);
        BOOST_CHECK_EQUAL(doc, 61U);
        doc = pIterator->skipTo(98);
        BOOST_CHECK_EQUAL(doc, 99U);
        doc = pIterator->skipTo(99);
        BOOST_CHECK_EQUAL(doc, -1U);
        doc = pIterator->skipTo(100);
        BOOST_CHECK_EQUAL(doc, -1U);
    }

    {
        boost::shared_ptr<IndexManager::FilterBitmapT> pFilterIdSet(new IndexManager::FilterBitmapT);

        pFilterIdSet->set(1);
        pFilterIdSet->set(2);
        pFilterIdSet->set(3);
        pFilterIdSet->set(4);
        pFilterIdSet->set(5);
        pFilterIdSet->set(6);
        pFilterIdSet->set(10);
        pFilterIdSet->set(20);
        pFilterIdSet->set(30);
        pFilterIdSet->set(33);
        pFilterIdSet->set(40);
        pFilterIdSet->set(50);
        pFilterIdSet->set(100);

        IndexManager::FilterTermDocFreqsT* pFilterTermDocFreqs = new IndexManager::FilterTermDocFreqsT(pFilterIdSet);
        AllDocumentIterator* pIterator = new AllDocumentIterator(pFilterTermDocFreqs, maxDoc);

        while(pIterator->next())
        {
            std::cout<<"doc "<<pIterator->doc()<<std::endl;
        }
    }

}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>refactor t_AllDocumentIterator.cpp<commit_after>#include <boost/test/unit_test.hpp>

#include <index-manager/IndexManager.h>
#include <search-manager/AllDocumentIterator.h>
#include <algorithm> // std::set_difference

using namespace sf1r;

namespace
{

static const sf1r::docid_t MAX_DOCID = 100;

static const sf1r::docid_t DELETE_DOCIDS[] = {
    1, 2, 3, 4, 5, 6,
    10, 20, 30, 33, 40, 50,
    100
};

static const std::size_t DELETE_DOCIDS_NUM =
    sizeof(DELETE_DOCIDS) / sizeof(DELETE_DOCIDS[0]);

AllDocumentIterator* createAllDocumentIterator()
{
    boost::shared_ptr<IndexManager::FilterBitmapT> pFilterIdSet(
        new IndexManager::FilterBitmapT);

    for (std::size_t i = 0; i < DELETE_DOCIDS_NUM; ++i)
    {
        pFilterIdSet->set(DELETE_DOCIDS[i]);
    }

    IndexManager::FilterTermDocFreqsT* pFilterTermDocFreqs =
        new IndexManager::FilterTermDocFreqsT(pFilterIdSet);

    return new AllDocumentIterator(pFilterTermDocFreqs, MAX_DOCID);

}

}

BOOST_AUTO_TEST_SUITE(AllDocumentIterator_Suite)

BOOST_AUTO_TEST_CASE(testSkipTo)
{
    const sf1r::docid_t skipTestData[][2] = {
        {2, 7}, {3, 7}, {4, 7}, {5, 7}, {6, 7},
        {8, 9}, {9, 11}, {10, 11}, {20, 21},
        {30, 31}, {40, 41}, {50, 51}, {60, 61},
        {98, 99}, {99, -1}, {100, -1}
    };
    const int num = sizeof(skipTestData) / sizeof(skipTestData[0]);

    AllDocumentIterator* pIterator = createAllDocumentIterator();

    for (int i = 0; i < num; ++i)
    {
        sf1r::docid_t target = skipTestData[i][0];
        sf1r::docid_t gold = skipTestData[i][1];
        BOOST_TEST_MESSAGE("target: " << target << ", gold: " << gold);

        BOOST_CHECK_EQUAL(pIterator->skipTo(target), gold);
    }

    delete pIterator;
}

BOOST_AUTO_TEST_CASE(testNext)
{
    std::vector<sf1r::docid_t> allDocIds;
    for (sf1r::docid_t docId = 1; docId <= MAX_DOCID; ++docId)
    {
        allDocIds.push_back(docId);
    }

    std::vector<sf1r::docid_t> existDocIds(allDocIds.size() - DELETE_DOCIDS_NUM);
    std::set_difference(allDocIds.begin(), allDocIds.end(),
                        DELETE_DOCIDS, DELETE_DOCIDS + DELETE_DOCIDS_NUM,
                        existDocIds.begin());

    AllDocumentIterator* pIterator = createAllDocumentIterator();

    for (std::vector<sf1r::docid_t>::const_iterator it = existDocIds.begin();
         it != existDocIds.end(); ++it)
    {
        BOOST_CHECK(pIterator->next());
        BOOST_CHECK_EQUAL(pIterator->doc(), *it);
        BOOST_TEST_MESSAGE("next doc: " << pIterator->doc());
    }

    delete pIterator;
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include <test/unit/math/test_ad.hpp>

TEST(MathMixMatFun, quadFormSym) {
  auto f = [](const auto& x, const auto& y) {
    return stan::math::quad_form_sym(x, y);
  };

  Eigen::MatrixXd a00;
  Eigen::MatrixXd a11(1, 1);
  a11 << 1;
  Eigen::MatrixXd b11(1, 1);
  b11 << -2;
  Eigen::MatrixXd a22(2, 2);
  a22 << 1, 2, 3, 4;
  Eigen::MatrixXd b22(2, 2);
  a22 << -3, -2, -10, 112;
  Eigen::MatrixXd a23(2, 3);
  a23 << 1, 2, 3, 4, 5, 6;
  Eigen::MatrixXd a42(4, 2);
  a42 << 100, 10, 0, 1, -3, -3, 5, 2;
  Eigen::MatrixXd a44(4, 4);
  a44 << 2, 3, 4, 5, 6, 10, 2, 2, 7, 2, 7, 1, 8, 2, 1, 112;

  Eigen::VectorXd v0(0);
  Eigen::VectorXd v1(1);
  v1 << 42;
  Eigen::VectorXd v2(2);
  v2 << -3, 13;
  Eigen::VectorXd v4(4);
  v4 << 100, 0, -3, 5;

  stan::test::expect_ad(f, a00, a00);
  stan::test::expect_ad(f, a11, b11);
  stan::test::expect_ad(f, a22, b22);
  stan::test::expect_ad(f, a44, a42);

  stan::test::expect_ad(f, a00, v0);
  stan::test::expect_ad(f, a11, v1);
  stan::test::expect_ad(f, a22, v2);
  stan::test::expect_ad(f, a44, v4);

  // asymmetric case should thorw
  Eigen::MatrixXd u(4, 4);
  u << 2, 3, 4, 5, 6, 10, 2, 2, 7, 2, 7, 1, 8, 2, 1, 112;
  Eigen::MatrixXd v(4, 2);
  v << 100, 10, 0, 1, -3, -3, 5, 2;
  stan::test::expect_ad(f, u, v);
}
<commit_msg>Fix quad_form_sym mix tests<commit_after>#include <test/unit/math/test_ad.hpp>
#include <test/unit/math/ad_tolerances.hpp>

TEST(MathMixMatFun, quadFormSym) {
  auto f = [](const auto& x, const auto& y) {
    // symmetrize the input matrix
    auto x_sym = ((x + x.transpose()) * 0.5).eval();
    return stan::math::quad_form_sym(x_sym, y);
  };

  Eigen::MatrixXd a00;
  Eigen::MatrixXd a11(1, 1);
  a11 << 1;
  Eigen::MatrixXd b11(1, 1);
  b11 << -2;
  Eigen::MatrixXd a22(2, 2);
  a22 << 1, 2, 3, 4;
  Eigen::MatrixXd b22(2, 2);
  b22 << -3, -2, -10, 112;
  Eigen::MatrixXd b23(2, 3);
  b23 << 1, 2, 3, 4, 5, 6;
  Eigen::MatrixXd b42(4, 2);
  b42 << 100, 10, 0, 1, -3, -3, 5, 2;
  Eigen::MatrixXd a44(4, 4);
  a44 << 2, 3, 4, 5, 6, 10, 2, 2, 7, 2, 7, 1, 8, 2, 1, 112;

  Eigen::VectorXd v0(0);
  Eigen::VectorXd v1(1);
  v1 << 42;
  Eigen::VectorXd v2(2);
  v2 << -3, 13;
  Eigen::VectorXd v4(4);
  v4 << 100, 0, -3, 5;

  stan::test::ad_tolerances tols;
  tols.hessian_hessian_ = 2e-1;
  tols.hessian_fvar_hessian_ = 2e-1;

  stan::test::expect_ad(f, a00, a00);
  stan::test::expect_ad(f, a11, b11);
  stan::test::expect_ad(tols, f, a22, b22);
  stan::test::expect_ad(f, a22, b23);
  stan::test::expect_ad(tols, f, a44, b42);

  stan::test::expect_ad(f, a00, v0);
  stan::test::expect_ad(f, a11, v1);
  stan::test::expect_ad(f, a22, v2);
  stan::test::expect_ad(tols, f, a44, v4);

  // asymmetric case should throw

  auto g = [](const auto& x, const auto& y) {
    return stan::math::quad_form_sym(x, y);
  };

  Eigen::MatrixXd u(4, 4);
  u << 2, 3, 4, 5, 6, 10, 2, 2, 7, 2, 7, 1, 8, 2, 1, 112;
  Eigen::MatrixXd v(4, 2);
  v << 100, 10, 0, 1, -3, -3, 5, 2;
  stan::test::expect_ad(g, u, v);
}
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------//
//                 █      █                                                   //
//                 ████████                                                   //
//               ██        ██                                                 //
//              ███  █  █  ███    CCBNodeLoader.cpp                           //
//              █ █        █ █    MonsterFramework                            //
//               ████████████                                                 //
//             █              █   Copyright (c) 2015 AmazingCow               //
//            █     █    █     █  www.AmazingCow.com                          //
//            █     █    █     █                                              //
//             █              █   N2OMatt - n2omatt@amazingcow.com            //
//               ████████████     www.amazingcow.com/n2omatt                  //
//                                                                            //
//                                                                            //
//                  This software is licensed as BSD-3                        //
//                 CHECK THE COPYING FILE TO MORE DETAILS                     //
//                                                                            //
//    Permission is granted to anyone to use this software for any purpose,   //
//   including commercial applications, and to alter it and redistribute it   //
//               freely, subject to the following restrictions:               //
//                                                                            //
//     0. You **CANNOT** change the type of the license.                      //
//     1. The origin of this software must not be misrepresented;             //
//        you must not claim that you wrote the original software.            //
//     2. If you use this software in a product, an acknowledgment in the     //
//        product IS HIGHLY APPRECIATED, both in source and binary forms.     //
//        (See opensource.AmazingCow.com/acknowledgment.html for details).    //
//        If you will not acknowledge, just send us a email. We'll be         //
//        *VERY* happy to see our work being used by other people. :)         //
//        The email is: acknowledgment.opensource@AmazingCow.com              //
//     3. Altered source versions must be plainly marked as such,             //
//        and must notbe misrepresented as being the original software.       //
//     4. This notice may not be removed or altered from any source           //
//        distribution.                                                       //
//     5. Most important, you must have fun. ;)                               //
//                                                                            //
//      Visit opensource.amazingcow.com for more open-source projects.        //
//                                                                            //
//                                  Enjoy :)                                  //
//----------------------------------------------------------------------------//

//Header
#include "CCBNodeLoader.h"
//std
#include <string>
//MonsterFramework
#include "MonsterFramework/include/Graphics/ILoadResolver.h"
#include "MonsterFramework/src/Graphics/private/CCBNodeLoader_Decoders.h"
#include "MonsterFramework/src/Graphics/private/CCBNodeLoader_PropertySetters.h"

//Usings
USING_NS_STD_CC_CD_MF

// MACROS //
#define _SET_PROPERTY_FUNCTION(_target_name_, _name_, _obj_, _value_) \
if(_name_ == #_target_name_) {                                        \
_set_ ## _target_name_(_obj_, _value_);                           \
}

// Public Methods //
void CCBNodeLoader::load(const cc::ValueMap &map, cc::Node *parent, mf::ILoadResolver *pResolver)
{
    //Retrieve the values
    auto baseClass               = map.at("baseClass"              ).asString();
    auto customClass             = map.at("customClass"            ).asString();
    auto children                = map.at("children"               ).asValueVector();
    auto memberVarAssignmentName = map.at("memberVarAssignmentName").asString();
    auto properties              = map.at("properties"             ).asValueVector();

    cc::ValueVector customProperties;
    auto customPropertiesIt = map.find("customProperties");
    if(customPropertiesIt != end(map))
         customProperties = map.at("customProperties").asValueVector();

    //LOG
//    MF_LOG("Loading a Node with BaseClass:(%s) with CustomClass:(%s) and MemberVarAssignment:(%s)",
//          baseClass.c_str(), customClass.c_str(), memberVarAssignmentName.c_str());

    //Create the node and assign its properties.
    cc::Node *node = nullptr;
    if(baseClass == "CCBFile")
    {
        auto ccbFilename = findCCBFilename(properties);
        node = pResolver->resolveCustomClass(ccbFilename);
    }
    else if(customClass.empty())
    {
        node = resolveDefaultClasses(baseClass);
    }
    else
    {
        node = resolveCustomClasses(customClass, pResolver, customProperties);
    }

    MF_ASSERT(node, "CCBNodeLoader - Node is null (%s)", baseClass.c_str());

    parent->addChild(node);
    assignProperties(node, properties, pResolver);

    //Resolve Custom Class.

    //Resolve Member Var Assignment
    pResolver->resolveVarAssignment(memberVarAssignmentName, node);

    //Create the Node's children.
    for(const auto &childItem : children)
    {
        CCBNodeLoader nodeLoader;
        nodeLoader.load(childItem.asValueMap(), node, pResolver);
    }
}
void CCBNodeLoader::loadNodeGraph(const cc::ValueMap &map, cc::Node *parent, mf::ILoadResolver *pResolver)
{
    auto children   = map.at("children"  ).asValueVector();
    auto properties = map.at("properties").asValueVector();

    assignProperties(parent, properties, pResolver);

    //Create the Node's children.
    for(const auto &childItem : children)
    {
        CCBNodeLoader nodeLoader;
        nodeLoader.load(childItem.asValueMap(), parent, pResolver);
    }
}

// Private Methods //
std::string CCBNodeLoader::findCCBFilename(const cc::ValueVector &properties)
{
    //Search for a property named ccbFile and return its value
    //if found, otherwise just return an empty string.
    for(auto it = begin(properties); it != end(properties); ++it)
    {
        const auto &item = it->asValueMap();

        if(item.at("name").asString() == "ccbFile")
            return item.at("value").asString();
    }
    return "";
}
cc::Node* CCBNodeLoader::assignProperties(cc::Node *obj, const cc::ValueVector &properties, ILoadResolver *pResolver)
{
    //Iterate for all properties.
    for(auto it = begin(properties); it != end(properties); ++it)
    {
        //Get the item.
        const auto &item  = it->asValueMap();
        //Get the name/value pair.
        const auto &name  = item.at("name" ).asString();
        const auto &value = item.at("value");

//        MF_LOG("CCBNodeLoader - %s", name.c_str());

        //Check if the name of property matches and set the property.
        _SET_PROPERTY_FUNCTION(anchorPoint,                  name, obj, value);
        _SET_PROPERTY_FUNCTION(scale,                        name, obj, value);
        _SET_PROPERTY_FUNCTION(ignoreAnchorPointForPosition, name, obj, value);
        _SET_PROPERTY_FUNCTION(isTouchEnabled,               name, obj, value);
        _SET_PROPERTY_FUNCTION(isAccelerometerEnabled,       name, obj, value);
        _SET_PROPERTY_FUNCTION(position,                     name, obj, value);
        _SET_PROPERTY_FUNCTION(displayFrame,                 name, obj, value);
        _SET_PROPERTY_FUNCTION(isEnabled,                    name, obj, value);
        _SET_PROPERTY_FUNCTION(normalSpriteFrame,            name, obj, value);
        _SET_PROPERTY_FUNCTION(selectedSpriteFrame,          name, obj, value);
        _SET_PROPERTY_FUNCTION(selectedSpriteFrame,          name, obj, value);
        _SET_PROPERTY_FUNCTION(color,                        name, obj, value);
        _SET_PROPERTY_FUNCTION(contentSize,                  name, obj, value);
        _SET_PROPERTY_FUNCTION(rotation,                     name, obj, value);
        _SET_PROPERTY_FUNCTION(fontName,                     name, obj, value);
        _SET_PROPERTY_FUNCTION(fontSize,                     name, obj, value);
        _SET_PROPERTY_FUNCTION(string,                       name, obj, value);
        _SET_PROPERTY_FUNCTION(opacity,                      name, obj, value);

        //Block is special, because we need the ILoadResolver
        //to communicate with the object owner class.
        if(name == "block")
            _set_block(obj, value, pResolver);
    }

    return obj;
}

cc::Node* CCBNodeLoader::resolveDefaultClasses(const std::string &baseClass)
{
    cc::Node *node;

    //Layer.
    if(baseClass == "CCLayer")
        node = cc::Layer::create();

    //LayerColor
    //COWTODO:: This is very strange. With we don't set a color here at craetion
    //of the LayerColor, later the object will not set any color. So any color
    //set in CCB won't be applied. I don't know why this behaviour is occurring
    //but know works in this way.
    else if(baseClass == "CCLayerColor")
        node = cc::LayerColor::create(cc::Color4B::BLUE);

    //Sprite
    else if(baseClass == "CCSprite")
        node = cc::Sprite::create();

    //Menu
    else if(baseClass == "CCMenu")
        node = cc::Menu::create();

    //MenuItem
    else if(baseClass == "CCMenuItemImage")
        node = cc::MenuItemSprite::create(nullptr, nullptr);

    //LabelTTF
    else if(baseClass == "CCLabelTTF")
        node = cc::Label::create();

    return node;
}
cc::Node* CCBNodeLoader::resolveCustomClasses(const std::string &customClass,
                                              mf::ILoadResolver *pResolver,
                                              const cc::ValueVector &customProperties)
{
//    cc::Node *node = nullptr;
//    if(customClass == "MFSpriteBatch")
//    {
//        auto imageName = customProperties.at(0).asValueMap().at("value").asString();
//        MF_LOG("%s", imageName.c_str());
//        auto texture = cc::SpriteFrameCache::getInstance()->addSpriteFramesWithFile(imageName);
//        node = cc::SpriteBatchNode::createWithTexture(texture);
//    }
//    return node;

    return pResolver->resolveCustomClass(customClass);
}

#undef _SET_PROPERTY_FUNCTION
<commit_msg>Initialize the pointer with nullptr<commit_after>//----------------------------------------------------------------------------//
//                 █      █                                                   //
//                 ████████                                                   //
//               ██        ██                                                 //
//              ███  █  █  ███    CCBNodeLoader.cpp                           //
//              █ █        █ █    MonsterFramework                            //
//               ████████████                                                 //
//             █              █   Copyright (c) 2015 AmazingCow               //
//            █     █    █     █  www.AmazingCow.com                          //
//            █     █    █     █                                              //
//             █              █   N2OMatt - n2omatt@amazingcow.com            //
//               ████████████     www.amazingcow.com/n2omatt                  //
//                                                                            //
//                                                                            //
//                  This software is licensed as BSD-3                        //
//                 CHECK THE COPYING FILE TO MORE DETAILS                     //
//                                                                            //
//    Permission is granted to anyone to use this software for any purpose,   //
//   including commercial applications, and to alter it and redistribute it   //
//               freely, subject to the following restrictions:               //
//                                                                            //
//     0. You **CANNOT** change the type of the license.                      //
//     1. The origin of this software must not be misrepresented;             //
//        you must not claim that you wrote the original software.            //
//     2. If you use this software in a product, an acknowledgment in the     //
//        product IS HIGHLY APPRECIATED, both in source and binary forms.     //
//        (See opensource.AmazingCow.com/acknowledgment.html for details).    //
//        If you will not acknowledge, just send us a email. We'll be         //
//        *VERY* happy to see our work being used by other people. :)         //
//        The email is: acknowledgment.opensource@AmazingCow.com              //
//     3. Altered source versions must be plainly marked as such,             //
//        and must notbe misrepresented as being the original software.       //
//     4. This notice may not be removed or altered from any source           //
//        distribution.                                                       //
//     5. Most important, you must have fun. ;)                               //
//                                                                            //
//      Visit opensource.amazingcow.com for more open-source projects.        //
//                                                                            //
//                                  Enjoy :)                                  //
//----------------------------------------------------------------------------//

//Header
#include "CCBNodeLoader.h"
//std
#include <string>
//MonsterFramework
#include "MonsterFramework/include/Graphics/ILoadResolver.h"
#include "MonsterFramework/src/Graphics/private/CCBNodeLoader_Decoders.h"
#include "MonsterFramework/src/Graphics/private/CCBNodeLoader_PropertySetters.h"

//Usings
USING_NS_STD_CC_CD_MF

// MACROS //
#define _SET_PROPERTY_FUNCTION(_target_name_, _name_, _obj_, _value_) \
if(_name_ == #_target_name_) {                                        \
_set_ ## _target_name_(_obj_, _value_);                           \
}

// Public Methods //
void CCBNodeLoader::load(const cc::ValueMap &map, cc::Node *parent, mf::ILoadResolver *pResolver)
{
    //Retrieve the values
    auto baseClass               = map.at("baseClass"              ).asString();
    auto customClass             = map.at("customClass"            ).asString();
    auto children                = map.at("children"               ).asValueVector();
    auto memberVarAssignmentName = map.at("memberVarAssignmentName").asString();
    auto properties              = map.at("properties"             ).asValueVector();

    cc::ValueVector customProperties;
    auto customPropertiesIt = map.find("customProperties");
    if(customPropertiesIt != end(map))
         customProperties = map.at("customProperties").asValueVector();

    //LOG
//    MF_LOG("Loading a Node with BaseClass:(%s) with CustomClass:(%s) and MemberVarAssignment:(%s)",
//          baseClass.c_str(), customClass.c_str(), memberVarAssignmentName.c_str());

    //Create the node and assign its properties.
    cc::Node *node = nullptr;
    if(baseClass == "CCBFile")
    {
        auto ccbFilename = findCCBFilename(properties);
        node = pResolver->resolveCustomClass(ccbFilename);
    }
    else if(customClass.empty())
    {
        node = resolveDefaultClasses(baseClass);
    }
    else
    {
        node = resolveCustomClasses(customClass, pResolver, customProperties);
    }

    MF_ASSERT(node, "CCBNodeLoader - Node is null (%s)", baseClass.c_str());

    parent->addChild(node);
    assignProperties(node, properties, pResolver);

    //Resolve Custom Class.

    //Resolve Member Var Assignment
    pResolver->resolveVarAssignment(memberVarAssignmentName, node);

    //Create the Node's children.
    for(const auto &childItem : children)
    {
        CCBNodeLoader nodeLoader;
        nodeLoader.load(childItem.asValueMap(), node, pResolver);
    }
}
void CCBNodeLoader::loadNodeGraph(const cc::ValueMap &map, cc::Node *parent, mf::ILoadResolver *pResolver)
{
    auto children   = map.at("children"  ).asValueVector();
    auto properties = map.at("properties").asValueVector();

    assignProperties(parent, properties, pResolver);

    //Create the Node's children.
    for(const auto &childItem : children)
    {
        CCBNodeLoader nodeLoader;
        nodeLoader.load(childItem.asValueMap(), parent, pResolver);
    }
}

// Private Methods //
std::string CCBNodeLoader::findCCBFilename(const cc::ValueVector &properties)
{
    //Search for a property named ccbFile and return its value
    //if found, otherwise just return an empty string.
    for(auto it = begin(properties); it != end(properties); ++it)
    {
        const auto &item = it->asValueMap();

        if(item.at("name").asString() == "ccbFile")
            return item.at("value").asString();
    }
    return "";
}
cc::Node* CCBNodeLoader::assignProperties(cc::Node *obj, const cc::ValueVector &properties, ILoadResolver *pResolver)
{
    //Iterate for all properties.
    for(auto it = begin(properties); it != end(properties); ++it)
    {
        //Get the item.
        const auto &item  = it->asValueMap();
        //Get the name/value pair.
        const auto &name  = item.at("name" ).asString();
        const auto &value = item.at("value");

//        MF_LOG("CCBNodeLoader - %s", name.c_str());

        //Check if the name of property matches and set the property.
        _SET_PROPERTY_FUNCTION(anchorPoint,                  name, obj, value);
        _SET_PROPERTY_FUNCTION(scale,                        name, obj, value);
        _SET_PROPERTY_FUNCTION(ignoreAnchorPointForPosition, name, obj, value);
        _SET_PROPERTY_FUNCTION(isTouchEnabled,               name, obj, value);
        _SET_PROPERTY_FUNCTION(isAccelerometerEnabled,       name, obj, value);
        _SET_PROPERTY_FUNCTION(position,                     name, obj, value);
        _SET_PROPERTY_FUNCTION(displayFrame,                 name, obj, value);
        _SET_PROPERTY_FUNCTION(isEnabled,                    name, obj, value);
        _SET_PROPERTY_FUNCTION(normalSpriteFrame,            name, obj, value);
        _SET_PROPERTY_FUNCTION(selectedSpriteFrame,          name, obj, value);
        _SET_PROPERTY_FUNCTION(selectedSpriteFrame,          name, obj, value);
        _SET_PROPERTY_FUNCTION(color,                        name, obj, value);
        _SET_PROPERTY_FUNCTION(contentSize,                  name, obj, value);
        _SET_PROPERTY_FUNCTION(rotation,                     name, obj, value);
        _SET_PROPERTY_FUNCTION(fontName,                     name, obj, value);
        _SET_PROPERTY_FUNCTION(fontSize,                     name, obj, value);
        _SET_PROPERTY_FUNCTION(string,                       name, obj, value);
        _SET_PROPERTY_FUNCTION(opacity,                      name, obj, value);

        //Block is special, because we need the ILoadResolver
        //to communicate with the object owner class.
        if(name == "block")
            _set_block(obj, value, pResolver);
    }

    return obj;
}

cc::Node* CCBNodeLoader::resolveDefaultClasses(const std::string &baseClass)
{
    cc::Node *node = nullptr;

    //Layer.
    if(baseClass == "CCLayer")
        node = cc::Layer::create();

    //LayerColor
    //COWTODO: Bug?
    //This is very strange. With we don't set a color here at craetion
    //of the LayerColor, later the object will not set any color. So any color
    //set in CCB won't be applied. I don't know why this behaviour is occurring
    //but know works in this way.
    else if(baseClass == "CCLayerColor")
        node = cc::LayerColor::create(cc::Color4B::BLUE);

    //Sprite
    else if(baseClass == "CCSprite")
        node = cc::Sprite::create();

    //Menu
    else if(baseClass == "CCMenu")
        node = cc::Menu::create();

    //MenuItem
    else if(baseClass == "CCMenuItemImage")
        node = cc::MenuItemSprite::create(nullptr, nullptr);

    //LabelTTF
    else if(baseClass == "CCLabelTTF")
        node = cc::Label::create();

    return node;
}
cc::Node* CCBNodeLoader::resolveCustomClasses(const std::string &customClass,
                                              mf::ILoadResolver *pResolver,
                                              const cc::ValueVector &customProperties)
{
//    cc::Node *node = nullptr;
//    if(customClass == "MFSpriteBatch")
//    {
//        auto imageName = customProperties.at(0).asValueMap().at("value").asString();
//        MF_LOG("%s", imageName.c_str());
//        auto texture = cc::SpriteFrameCache::getInstance()->addSpriteFramesWithFile(imageName);
//        node = cc::SpriteBatchNode::createWithTexture(texture);
//    }
//    return node;

    return pResolver->resolveCustomClass(customClass);
}

#undef _SET_PROPERTY_FUNCTION
<|endoftext|>


<commit_before>#include "evpp/inner_pre.h"
#include "evpp/event_loop_thread_pool.h"
#include "evpp/event_loop.h"

namespace evpp {

EventLoopThreadPool::EventLoopThreadPool(EventLoop* base_loop, uint32_t thread_number)
    : base_loop_(base_loop),
      started_(false),
      thread_num_(thread_number),
      next_(0) {}

EventLoopThreadPool::~EventLoopThreadPool() {
    assert(thread_num_ == threads_.size());

    for (uint32_t i = 0; i < thread_num_; i++) {
        assert(threads_[i]->IsStopped());
    }

    threads_.clear();
}

bool EventLoopThreadPool::Start(bool wait_until_thread_started) {
    assert(!started_);

    if (started_) {
        return true;
    }

    for (uint32_t i = 0; i < thread_num_; ++i) {
        std::stringstream ss;
        ss << "EventLoopThreadPool-thread-" << i << "th";
        EventLoopThreadPtr t(new EventLoopThread());

        if (!t->Start(wait_until_thread_started)) {
            //FIXME error process
            LOG_ERROR << "start thread failed!";
            return false;
        }

        t->SetName(ss.str());
        threads_.push_back(t);
    }

    started_ = true;
    return true;
}

void EventLoopThreadPool::Stop(bool wait_thread_exit) {
    for (uint32_t i = 0; i < thread_num_; ++i) {
        EventLoopThreadPtr& t = threads_[i];
        t->Stop(wait_thread_exit);
    }

    if (thread_num_ > 0 && wait_thread_exit) {
        while (!IsStopped()) {
            usleep(1);
        }
    }

    started_ = false;
}

bool EventLoopThreadPool::IsRunning() const {
    for (uint32_t i = 0; i < thread_num_; ++i) {
        const EventLoopThreadPtr& t = threads_[i];

        if (!t->IsRunning()) {
            return false;
        }
    }

    return started_;
}

bool EventLoopThreadPool::IsStopped() const {
    if (thread_num_ == 0) {
        return !started_;
    }

    for (uint32_t i = 0; i < thread_num_; ++i) {
        const EventLoopThreadPtr& t = threads_[i];

        if (!t->IsStopped()) {
            return false;
        }
    }

    return true;
}

EventLoop* EventLoopThreadPool::GetNextLoop() {
    EventLoop* loop = base_loop_;

    if (!threads_.empty()) {
        // No need to lock here
        int64_t next = next_.fetch_add(1);
        next = next % threads_.size();
        loop = (threads_[next])->event_loop();
    }

    return loop;
}

EventLoop* EventLoopThreadPool::GetNextLoopWithHash(uint64_t hash) {
    EventLoop* loop = base_loop_;

    if (!threads_.empty()) {
        uint64_t next = hash % threads_.size();
        loop = (threads_[next])->event_loop();
    }

    return loop;
}

uint32_t EventLoopThreadPool::thread_num() const {
    return thread_num_;
}

}
<commit_msg>Fix EventLoopThreadPool::IsRunning() bug when it is not started<commit_after>#include "evpp/inner_pre.h"
#include "evpp/event_loop_thread_pool.h"
#include "evpp/event_loop.h"

namespace evpp {

EventLoopThreadPool::EventLoopThreadPool(EventLoop* base_loop, uint32_t thread_number)
    : base_loop_(base_loop),
      started_(false),
      thread_num_(thread_number),
      next_(0) {}

EventLoopThreadPool::~EventLoopThreadPool() {
    assert(thread_num_ == threads_.size());

    for (uint32_t i = 0; i < thread_num_; i++) {
        assert(threads_[i]->IsStopped());
    }

    threads_.clear();
}

bool EventLoopThreadPool::Start(bool wait_until_thread_started) {
    assert(!started_);

    if (started_) {
        return true;
    }

    for (uint32_t i = 0; i < thread_num_; ++i) {
        std::stringstream ss;
        ss << "EventLoopThreadPool-thread-" << i << "th";
        EventLoopThreadPtr t(new EventLoopThread());

        if (!t->Start(wait_until_thread_started)) {
            //FIXME error process
            LOG_ERROR << "start thread failed!";
            return false;
        }

        t->SetName(ss.str());
        threads_.push_back(t);
    }

    started_ = true;
    return true;
}

void EventLoopThreadPool::Stop(bool wait_thread_exit) {
    for (uint32_t i = 0; i < thread_num_; ++i) {
        EventLoopThreadPtr& t = threads_[i];
        t->Stop(wait_thread_exit);
    }

    if (thread_num_ > 0 && wait_thread_exit) {
        while (!IsStopped()) {
            usleep(1);
        }
    }

    started_ = false;
}

bool EventLoopThreadPool::IsRunning() const {
    if (!started_) {
        return false;
    }

    for (uint32_t i = 0; i < thread_num_; ++i) {
        const EventLoopThreadPtr& t = threads_[i];

        if (!t->IsRunning()) {
            return false;
        }
    }

    return started_;
}

bool EventLoopThreadPool::IsStopped() const {
    if (thread_num_ == 0) {
        return !started_;
    }

    for (uint32_t i = 0; i < thread_num_; ++i) {
        const EventLoopThreadPtr& t = threads_[i];

        if (!t->IsStopped()) {
            return false;
        }
    }

    return true;
}

EventLoop* EventLoopThreadPool::GetNextLoop() {
    EventLoop* loop = base_loop_;

    if (!threads_.empty()) {
        // No need to lock here
        int64_t next = next_.fetch_add(1);
        next = next % threads_.size();
        loop = (threads_[next])->event_loop();
    }

    return loop;
}

EventLoop* EventLoopThreadPool::GetNextLoopWithHash(uint64_t hash) {
    EventLoop* loop = base_loop_;

    if (!threads_.empty()) {
        uint64_t next = hash % threads_.size();
        loop = (threads_[next])->event_loop();
    }

    return loop;
}

uint32_t EventLoopThreadPool::thread_num() const {
    return thread_num_;
}

}
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "ft_mscalableimage.h"
#include "mapplication.h"
#include <corelib/theme/mtheme.h>
#include <corelib/painting/mscalableimage.h>
#include <QtTest>
#include <QPainter>

QVector<QPixmap *> pixmaps;

const int BLOCK_SIZE = 10;
QString COLOR_TOPLEFT("#00ff00");
QString COLOR_TOP("#ff0000");
QString COLOR_TOPRIGHT("#00ff00");
QString COLOR_LEFT("#ff0000");
QString COLOR_CENTER("#0000ff");
QString COLOR_RIGHT("#ff0000");
QString COLOR_BOTTOMLEFT("#00ff00");
QString COLOR_BOTTOM("#ff0000");
QString COLOR_BOTTOMRIGHT("#00ff00");

// Override mtheme pixmap, to provide our own test pixmaps
const QPixmap *createPixmap(const QString &id, const QSize &size)
{
    if (id == "single_image") {
        QSize image_size = size.isValid() ? size : QSize(512, 512);
        QPixmap *pixmap = new QPixmap(image_size);

        int center_width = image_size.width() - 2 * BLOCK_SIZE;
        int center_height = image_size.height() - 2 * BLOCK_SIZE;

        QPainter painter(pixmap);
        painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
        painter.fillRect(0, 0, BLOCK_SIZE, BLOCK_SIZE, QColor(COLOR_TOPLEFT));
        painter.fillRect(BLOCK_SIZE, 0, center_width, BLOCK_SIZE, QColor(COLOR_TOP));
        painter.fillRect(BLOCK_SIZE + center_width, 0, BLOCK_SIZE, BLOCK_SIZE, QColor(COLOR_TOPRIGHT));
        painter.fillRect(0, BLOCK_SIZE, BLOCK_SIZE, center_height, QColor(COLOR_LEFT));
        painter.fillRect(BLOCK_SIZE, BLOCK_SIZE, center_width, center_height, QColor(COLOR_CENTER));
        painter.fillRect(BLOCK_SIZE + center_width, BLOCK_SIZE, BLOCK_SIZE, center_height, QColor(COLOR_RIGHT));
        painter.fillRect(0, BLOCK_SIZE + center_height, BLOCK_SIZE, BLOCK_SIZE, QColor(COLOR_BOTTOMLEFT));
        painter.fillRect(BLOCK_SIZE, BLOCK_SIZE + center_height, center_width, BLOCK_SIZE, QColor(COLOR_BOTTOM));
        painter.fillRect(BLOCK_SIZE + center_width, BLOCK_SIZE + center_height, BLOCK_SIZE, BLOCK_SIZE, QColor(COLOR_BOTTOMRIGHT));

        // debug
        //pixmap->save("test2.png");
        return pixmap;
    } else {
        QPixmap *pixmap = new QPixmap(size.isValid() ? size : QSize(BLOCK_SIZE, BLOCK_SIZE));
        pixmap->fill(QColor(id));
        pixmaps.push_back(pixmap);
        return pixmap;
    }
}

Ft_MScalableImage::Ft_MScalableImage()
{
}

void Ft_MScalableImage::init()
{
    m_subject = new MScalableImage();
}

void Ft_MScalableImage::cleanup()
{
    for (int i = 0; i < pixmaps.size(); i++) {
        delete pixmaps[i];
    }
    pixmaps.clear();

    delete m_subject;
}

MApplication *app;

void Ft_MScalableImage::initTestCase()
{
    static int argc = 1;
    static char *app_name[1] = { (char *) "./Ft_MScalableImage" };
    app = new MApplication(argc, app_name);
}

void Ft_MScalableImage::cleanupTestCase()
{
    delete app;
}

bool isImageBlockColor(const QImage &image, const QRect &rect, const QString &colorid)
{
    QColor color(colorid);
    QImage copy = image.copy(rect);
    for (int y = 0; y < copy.height(); y++) {
        for (int x = 0; x < copy.width(); x++) {
            if (copy.pixel(x, y) != color.rgb()) {
                return false;
            }
        }
    }

    return true;
}

void Ft_MScalableImage::test_construction()
{
    // topleft, topright, bottomleft, bottomright, top, left, bottom, right, center
    const QPixmap *pm = createPixmap("single_image", QSize(-1, -1));

    m_subject->setPixmap(pm);
    m_subject->setBorders(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);

    // adjust these to draw different size images to different location
    QSize image_size    = QSize(512, 512);

    QPoint paint_offset = QPoint(6, 6);
    QSize paint_size    = QSize(256, 256);

    QPixmap canvas(image_size);
    canvas.fill(Qt::black);

    QPainter painter(&canvas);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, false);

    // draw from image-offset to the edge of the canvas
    m_subject->draw(paint_offset, paint_size, &painter);
    // save, debug
    //canvas.save("/tmp/test.png");

    // check that the image looks proper,
    // clip only the part that should contain the drawn data
    QRect fillRegion(paint_offset, paint_size);
    QImage image = canvas.toImage().copy(fillRegion);

    // calculate the size for the center block
    int center_width = paint_size.width() - 2 * BLOCK_SIZE;
    int center_height = paint_size.height() - 2 * BLOCK_SIZE;

    // corners
    QCOMPARE(isImageBlockColor(image, QRect(0, 0, BLOCK_SIZE, BLOCK_SIZE), COLOR_TOPLEFT), true);
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE + center_width, 0, BLOCK_SIZE, BLOCK_SIZE), COLOR_TOPRIGHT), true);
    QCOMPARE(isImageBlockColor(image, QRect(0, BLOCK_SIZE + center_height, BLOCK_SIZE, BLOCK_SIZE), COLOR_BOTTOMLEFT), true);
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE + center_width, BLOCK_SIZE + center_height, BLOCK_SIZE, BLOCK_SIZE), COLOR_BOTTOMRIGHT), true);

    // edges
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE, 0, center_width, BLOCK_SIZE), COLOR_TOP), true);
    QCOMPARE(isImageBlockColor(image, QRect(0, BLOCK_SIZE, BLOCK_SIZE, center_height), COLOR_LEFT), true);
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE, BLOCK_SIZE + center_height, center_width, BLOCK_SIZE), COLOR_BOTTOM), true);
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE + center_width, BLOCK_SIZE, BLOCK_SIZE, center_height), COLOR_RIGHT), true);

    // center
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE, BLOCK_SIZE, center_width, center_height), COLOR_CENTER), true);
}

QTEST_APPLESS_MAIN(Ft_MScalableImage)
<commit_msg>Changes: Fixed failing ft_mscalableimage.<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "ft_mscalableimage.h"
#include "mapplication.h"
#include <corelib/theme/mtheme.h>
#include <corelib/painting/mscalableimage.h>
#include <QtTest>
#include <QPainter>

QVector<QPixmap *> pixmaps;

const int BLOCK_SIZE = 10;
QString COLOR_TOPLEFT("#00ff00");
QString COLOR_TOP("#ff0000");
QString COLOR_TOPRIGHT("#00ff00");
QString COLOR_LEFT("#ff0000");
QString COLOR_CENTER("#0000ff");
QString COLOR_RIGHT("#ff0000");
QString COLOR_BOTTOMLEFT("#00ff00");
QString COLOR_BOTTOM("#ff0000");
QString COLOR_BOTTOMRIGHT("#00ff00");

// Override mtheme pixmap, to provide our own test pixmaps
const QPixmap *createPixmap(const QString &id, const QSize &size)
{
    if (id == "single_image") {
        QSize image_size = size.isValid() ? size : QSize(512, 512);
        QPixmap *pixmap = new QPixmap(image_size);

        int center_width = image_size.width() - 2 * BLOCK_SIZE;
        int center_height = image_size.height() - 2 * BLOCK_SIZE;

        QPainter painter(pixmap);
        painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
        painter.fillRect(0, 0, BLOCK_SIZE, BLOCK_SIZE, QColor(COLOR_TOPLEFT));
        painter.fillRect(BLOCK_SIZE, 0, center_width, BLOCK_SIZE, QColor(COLOR_TOP));
        painter.fillRect(BLOCK_SIZE + center_width, 0, BLOCK_SIZE, BLOCK_SIZE, QColor(COLOR_TOPRIGHT));
        painter.fillRect(0, BLOCK_SIZE, BLOCK_SIZE, center_height, QColor(COLOR_LEFT));
        painter.fillRect(BLOCK_SIZE, BLOCK_SIZE, center_width, center_height, QColor(COLOR_CENTER));
        painter.fillRect(BLOCK_SIZE + center_width, BLOCK_SIZE, BLOCK_SIZE, center_height, QColor(COLOR_RIGHT));
        painter.fillRect(0, BLOCK_SIZE + center_height, BLOCK_SIZE, BLOCK_SIZE, QColor(COLOR_BOTTOMLEFT));
        painter.fillRect(BLOCK_SIZE, BLOCK_SIZE + center_height, center_width, BLOCK_SIZE, QColor(COLOR_BOTTOM));
        painter.fillRect(BLOCK_SIZE + center_width, BLOCK_SIZE + center_height, BLOCK_SIZE, BLOCK_SIZE, QColor(COLOR_BOTTOMRIGHT));

        // debug
        //pixmap->save("test2.png");
        return pixmap;
    } else {
        QPixmap *pixmap = new QPixmap(size.isValid() ? size : QSize(BLOCK_SIZE, BLOCK_SIZE));
        pixmap->fill(QColor(id));
        pixmaps.push_back(pixmap);
        return pixmap;
    }
}

Ft_MScalableImage::Ft_MScalableImage()
{
}

void Ft_MScalableImage::init()
{
    m_subject = new MScalableImage();
}

void Ft_MScalableImage::cleanup()
{
    for (int i = 0; i < pixmaps.size(); i++) {
        delete pixmaps[i];
    }
    pixmaps.clear();

    delete m_subject;
}

MApplication *app;

void Ft_MScalableImage::initTestCase()
{
    static int argc = 1;
    static char *app_name[1] = { (char *) "./Ft_MScalableImage" };
    app = new MApplication(argc, app_name);
}

void Ft_MScalableImage::cleanupTestCase()
{
    delete app;
}

bool isImageBlockColor(const QImage &image, const QRect &rect, const QString &colorid)
{
    QColor color(colorid);
    QImage copy = image.copy(rect);
    for (int y = 0; y < copy.height(); y++) {
        for (int x = 0; x < copy.width(); x++) {
            if (copy.pixel(x, y) != color.rgb()) {
                return false;
            }
        }
    }

    return true;
}

void Ft_MScalableImage::test_construction()
{
    // topleft, topright, bottomleft, bottomright, top, left, bottom, right, center
    const QPixmap *pm = createPixmap("single_image", QSize(-1, -1));

    m_subject->setPixmap(pm);
    m_subject->setBorders(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);

    // adjust these to draw different size images to different location
    QSize image_size    = QSize(512, 512);

    QPoint paint_offset = QPoint(6, 6);
    QSize paint_size    = QSize(256, 256);

    QPixmap canvas(image_size);
    canvas.fill(Qt::black);

    QPainter painter(&canvas);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, false);

    // draw from image-offset to the edge of the canvas
    m_subject->draw(paint_offset, paint_size, &painter);
    // save, debug
    //canvas.save("/tmp/test.png");

    // check that the image looks proper,
    // clip only the part that should contain the drawn data
    QRect fillRegion(paint_offset, paint_size);
    QImage image = canvas.toImage().copy(fillRegion);

    // calculate the size for the center block
    int center_width = paint_size.width() - 2 * BLOCK_SIZE;
    int center_height = paint_size.height() - 2 * BLOCK_SIZE;

    // corners
    QCOMPARE(isImageBlockColor(image, QRect(2, 2, BLOCK_SIZE-2, BLOCK_SIZE-2), COLOR_TOPLEFT), true);
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE + center_width + 2, 2, BLOCK_SIZE-2, BLOCK_SIZE-2), COLOR_TOPRIGHT), true);
    QCOMPARE(isImageBlockColor(image, QRect(2, BLOCK_SIZE + center_height + 2, BLOCK_SIZE-2, BLOCK_SIZE-2), COLOR_BOTTOMLEFT), true);
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE + center_width + 2, BLOCK_SIZE + center_height + 2, BLOCK_SIZE - 2, BLOCK_SIZE - 2), COLOR_BOTTOMRIGHT), true);

    // edges
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE+2, 2, center_width-2, BLOCK_SIZE-2), COLOR_TOP), true);
    QCOMPARE(isImageBlockColor(image, QRect(2, BLOCK_SIZE+2, BLOCK_SIZE-2, center_height-2), COLOR_LEFT), true);
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE+2, BLOCK_SIZE + center_height + 2, center_width-2, BLOCK_SIZE-2), COLOR_BOTTOM), true);
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE + center_width + 2, BLOCK_SIZE + 2, BLOCK_SIZE-2, center_height-2), COLOR_RIGHT), true);

    // center
    QCOMPARE(isImageBlockColor(image, QRect(BLOCK_SIZE, BLOCK_SIZE, center_width, center_height), COLOR_CENTER), true);
}

QTEST_APPLESS_MAIN(Ft_MScalableImage)
<|endoftext|>


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

#include <algorithm>
#include <cassert>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <setjmp.h>

#include "IECore/JPEGImageReader.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/VectorTypedData.h"
#include "IECore/ByteOrder.h"
#include "IECore/MessageHandler.h"
#include "IECore/ImagePrimitive.h"
#include "IECore/FileNameParameter.h"
#include "IECore/BoxOps.h"

#include "boost/format.hpp"

extern "C"
{
#include "jpeglib.h"
}

using namespace IECore;
using namespace boost;
using namespace Imath;
using namespace std;

const Reader::ReaderDescription <JPEGImageReader> JPEGImageReader::m_readerDescription ("jpeg jpg");

JPEGImageReader::JPEGImageReader() :
		ImageReader( "JPEGImageReader", "Reads Joint Photographic Experts Group (JPEG) files" )
{
}

JPEGImageReader::JPEGImageReader(const string & fileName) :
		ImageReader( "JPEGImageReader", "Reads Joint Photographic Experts Group (JPEG) files" )
{
	m_fileNameParameter->setTypedValue( fileName );
}

JPEGImageReader::~JPEGImageReader()
{
}

bool JPEGImageReader::canRead( const string &fileName )
{
	// attempt to open the file
	ifstream in(fileName.c_str());
	if (!in.is_open())
	{
		return false;
	}

	// check the magic number of the input file
	// a jpeg should have 0xffd8ffe0 from offset 0
	unsigned int magic;
	in.seekg(0, ios_base::beg);
	in.read((char *) &magic, sizeof(unsigned int));

	return magic == 0xe0ffd8ff || magic == 0xffd8ffe0 || magic == 0xe1ffd8ff || magic == 0xffd8ffe1 ;
}

void JPEGImageReader::channelNames( vector<string> &names )
{
	open( true );
	names.clear();

	if ( m_numChannels == 3 )
	{
		names.push_back("R");
		names.push_back("G");
		names.push_back("B");
	}
	else
	{
		assert ( m_numChannels == 1 );
		names.push_back("Y");
	}
}

bool JPEGImageReader::isComplete()
{
	return open( false );
}

Imath::Box2i JPEGImageReader::dataWindow()
{
	open( true );

	return Box2i( V2i( 0, 0 ), V2i( m_bufferWidth - 1, m_bufferHeight - 1 ) );
}

Imath::Box2i JPEGImageReader::displayWindow()
{
	return dataWindow();
}

DataPtr JPEGImageReader::readChannel( const std::string &name, const Imath::Box2i &dataWindow )
{
	open( true );

	int channelOffset = 0;
	if ( name == "R" )
	{
		channelOffset = 0;
	}
	else if ( name == "G" )
	{
		channelOffset = 1;
	}
	else if ( name == "B" )
	{
		channelOffset = 2;
	}
	else if ( name == "Y" )
	{
		channelOffset = 0;
	}
	else
	{
		throw IOException( ( boost::format( "JPEGImageReader: Could not find channel \"%s\" while reading %s" ) % name % m_bufferFileName ).str() );
	}

	assert( channelOffset < m_numChannels );

	HalfVectorDataPtr dataContainer = new HalfVectorData();
	HalfVectorData::ValueType &data = dataContainer->writable();
	int area = ( dataWindow.size().x + 1 ) * ( dataWindow.size().y + 1 );
	assert( area >= 0 );
	data.resize( area );

	int dataWidth = 1 + dataWindow.size().x;

	int dataY = 0;

	for ( int y = dataWindow.min.y; y <= dataWindow.max.y; ++y, ++dataY )
	{
		HalfVectorData::ValueType::size_type dataOffset = dataY * dataWidth;

		for ( int x = dataWindow.min.x; x <= dataWindow.max.x; ++x, ++dataOffset )
		{
			assert( dataOffset < data.size() );

			data[dataOffset] = m_buffer[ m_numChannels * ( y * m_bufferWidth + x ) + channelOffset ] / 255.0f;
		}
	}

	return dataContainer;
}

struct JPEGReaderErrorHandler : public jpeg_error_mgr
{
	jmp_buf m_jmpBuffer;
	char m_errorMessage[JMSG_LENGTH_MAX];

	static void errorExit ( j_common_ptr cinfo )
	{
		assert( cinfo );
		assert( cinfo->err );

		JPEGReaderErrorHandler* errorHandler = static_cast< JPEGReaderErrorHandler* >( cinfo->err );
		( *cinfo->err->format_message )( cinfo, errorHandler->m_errorMessage );
		longjmp( errorHandler->m_jmpBuffer, 1 );
	}
};

bool JPEGImageReader::open( bool throwOnFailure )
{
	if ( fileName() == m_bufferFileName )
	{
		return true;
	}

	m_bufferFileName = fileName();
	m_buffer.clear();

	FILE *inFile = 0;
	try
	{
		// open the file
		inFile = fopen( m_bufferFileName.c_str(), "rb" );
		if ( !inFile )
		{
			throw IOException( ( boost::format( "JPEGImageReader: Could not open file %s" ) % m_bufferFileName ).str() );
		}

		struct jpeg_decompress_struct cinfo;

		try
		{
			JPEGReaderErrorHandler errorHandler;

			/// Setup error handler
			cinfo.err = jpeg_std_error( &errorHandler );

			/// Override fatal error and warning handlers
			errorHandler.error_exit = JPEGReaderErrorHandler::errorExit;
			errorHandler.output_message = JPEGReaderErrorHandler::errorExit;

			/// If we reach here then libjpeg has called our error handler, in which we've saved a copy of the
			/// error such that we might throw it as an exception.
			if ( setjmp( errorHandler.m_jmpBuffer ) )
			{
				throw IOException( std::string( "JPEGImageReader: " ) + errorHandler.m_errorMessage );
			}

			/// Initialize decompressor to read from "inFile"
			jpeg_create_decompress( &cinfo );
			jpeg_stdio_src( &cinfo, inFile );
			jpeg_read_header( &cinfo, TRUE );

			/// Start decompression
			jpeg_start_decompress( &cinfo );

			m_numChannels = cinfo.output_components;

			if ( m_numChannels != 1 && m_numChannels != 3 )
			{
				throw IOException( ( boost::format( "JPEGImageReader: Unsupported number of channels (%d) while opening file %s" ) % m_numChannels % m_bufferFileName ).str() );
			}

			if ( cinfo.out_color_space == JCS_GRAYSCALE )
			{
				assert( m_numChannels == 1 );
			}
			else if ( cinfo.out_color_space != JCS_RGB )
			{
				throw IOException( ( boost::format( "JPEGImageReader: Unsupported colorspace (%d) while opening file %s" ) % cinfo.out_color_space % m_bufferFileName ).str() );
			}

			/// Create buffer
			int rowStride = cinfo.output_width * cinfo.output_components;
			m_buffer.resize( rowStride * cinfo.output_height, 0 );
			;
			m_bufferWidth = cinfo.output_width;
			m_bufferHeight = cinfo.output_height;

			/// Read scanlines one at a time.
			while (cinfo.output_scanline < cinfo.output_height)
			{
				unsigned char *rowPointer[1] = { &m_buffer[0] + rowStride * cinfo.output_scanline };
				jpeg_read_scanlines( &cinfo, rowPointer, 1 );
			}

			/// Finish decompression
			jpeg_finish_decompress( &cinfo );
			jpeg_destroy_decompress( &cinfo );
		}
		catch ( Exception &e )
		{
			jpeg_destroy_decompress( &cinfo );

			throw;
		}
		catch ( std::exception &e )
		{
			jpeg_destroy_decompress( &cinfo );

			throw IOException( ( boost::format( "JPEGImageReader : %s" ) % e.what() ).str() );
		}
		catch ( ... )
		{
			jpeg_destroy_decompress( &cinfo );

			throw IOException( "JPEGImageReader: Unexpected error" );
		}

		fclose( inFile );
	}
	catch (...)
	{
		if ( inFile )
		{
			fclose( inFile );
		}

		if ( throwOnFailure )
		{
			throw;
		}
		else
		{
			return false;
		}
	}

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

#include <algorithm>
#include <cassert>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <setjmp.h>

#include "IECore/JPEGImageReader.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/VectorTypedData.h"
#include "IECore/ByteOrder.h"
#include "IECore/MessageHandler.h"
#include "IECore/ImagePrimitive.h"
#include "IECore/FileNameParameter.h"
#include "IECore/BoxOps.h"

#include "boost/format.hpp"

extern "C"
{
#include "jpeglib.h"
}

using namespace IECore;
using namespace boost;
using namespace Imath;
using namespace std;

const Reader::ReaderDescription <JPEGImageReader> JPEGImageReader::m_readerDescription ("jpeg jpg");

JPEGImageReader::JPEGImageReader() :
		ImageReader( "JPEGImageReader", "Reads Joint Photographic Experts Group (JPEG) files" )
{
}

JPEGImageReader::JPEGImageReader(const string & fileName) :
		ImageReader( "JPEGImageReader", "Reads Joint Photographic Experts Group (JPEG) files" )
{
	m_fileNameParameter->setTypedValue( fileName );
}

JPEGImageReader::~JPEGImageReader()
{
}

bool JPEGImageReader::canRead( const string &fileName )
{
	// attempt to open the file
	ifstream in(fileName.c_str());
	if (!in.is_open())
	{
		return false;
	}

	// check the magic number of the input file
	// a jpeg should have 0xffd8ffe0 from offset 0
	unsigned int magic;
	in.seekg(0, ios_base::beg);
	in.read((char *) &magic, sizeof(unsigned int));

	return magic == 0xe0ffd8ff || magic == 0xffd8ffe0 || magic == 0xe1ffd8ff || magic == 0xffd8ffe1 ;
}

void JPEGImageReader::channelNames( vector<string> &names )
{
	open( true );
	names.clear();

	if ( m_numChannels == 3 )
	{
		names.push_back("R");
		names.push_back("G");
		names.push_back("B");
	}
	else
	{
		assert ( m_numChannels == 1 );
		names.push_back("Y");
	}
}

bool JPEGImageReader::isComplete()
{
	return open( false );
}

Imath::Box2i JPEGImageReader::dataWindow()
{
	open( true );

	return Box2i( V2i( 0, 0 ), V2i( m_bufferWidth - 1, m_bufferHeight - 1 ) );
}

Imath::Box2i JPEGImageReader::displayWindow()
{
	return dataWindow();
}

DataPtr JPEGImageReader::readChannel( const std::string &name, const Imath::Box2i &dataWindow )
{
	open( true );

	int channelOffset = 0;
	if ( name == "R" )
	{
		channelOffset = 0;
	}
	else if ( name == "G" )
	{
		channelOffset = 1;
	}
	else if ( name == "B" )
	{
		channelOffset = 2;
	}
	else if ( name == "Y" )
	{
		channelOffset = 0;
	}
	else
	{
		throw IOException( ( boost::format( "JPEGImageReader: Could not find channel \"%s\" while reading %s" ) % name % m_bufferFileName ).str() );
	}

	assert( channelOffset < m_numChannels );

	HalfVectorDataPtr dataContainer = new HalfVectorData();
	HalfVectorData::ValueType &data = dataContainer->writable();
	int area = ( dataWindow.size().x + 1 ) * ( dataWindow.size().y + 1 );
	assert( area >= 0 );
	data.resize( area );

	int dataWidth = 1 + dataWindow.size().x;

	int dataY = 0;

	for ( int y = dataWindow.min.y; y <= dataWindow.max.y; ++y, ++dataY )
	{
		HalfVectorData::ValueType::size_type dataOffset = dataY * dataWidth;

		for ( int x = dataWindow.min.x; x <= dataWindow.max.x; ++x, ++dataOffset )
		{
			assert( dataOffset < data.size() );

			data[dataOffset] = m_buffer[ m_numChannels * ( y * m_bufferWidth + x ) + channelOffset ] / 255.0f;
		}
	}

	return dataContainer;
}

struct JPEGReaderErrorHandler : public jpeg_error_mgr
{
	jmp_buf m_jmpBuffer;
	char m_errorMessage[JMSG_LENGTH_MAX];

	static void errorExit ( j_common_ptr cinfo )
	{
		assert( cinfo );
		assert( cinfo->err );

		JPEGReaderErrorHandler* errorHandler = static_cast< JPEGReaderErrorHandler* >( cinfo->err );
		( *cinfo->err->format_message )( cinfo, errorHandler->m_errorMessage );
		longjmp( errorHandler->m_jmpBuffer, 1 );
	}
};

bool JPEGImageReader::open( bool throwOnFailure )
{
	if ( fileName() == m_bufferFileName )
	{
		return true;
	}

	m_bufferFileName = fileName();
	m_buffer.clear();

	FILE *inFile = 0;
	try
	{
		// open the file
		inFile = fopen( m_bufferFileName.c_str(), "rb" );
		if ( !inFile )
		{
			throw IOException( ( boost::format( "JPEGImageReader: Could not open file %s" ) % m_bufferFileName ).str() );
		}

		struct jpeg_decompress_struct cinfo;

		try
		{
			JPEGReaderErrorHandler errorHandler;

			/// Setup error handler
			cinfo.err = jpeg_std_error( &errorHandler );

			/// Override fatal error and warning handlers
			errorHandler.error_exit = JPEGReaderErrorHandler::errorExit;
			errorHandler.output_message = JPEGReaderErrorHandler::errorExit;

			/// If we reach here then libjpeg has called our error handler, in which we've saved a copy of the
			/// error such that we might throw it as an exception.
			if ( setjmp( errorHandler.m_jmpBuffer ) )
			{
				throw IOException( std::string( "JPEGImageReader: " ) + errorHandler.m_errorMessage );
			}

			/// Initialize decompressor to read from "inFile"
			jpeg_create_decompress( &cinfo );
			jpeg_stdio_src( &cinfo, inFile );
			jpeg_read_header( &cinfo, TRUE );

			/// Start decompression
			jpeg_start_decompress( &cinfo );

			m_numChannels = cinfo.output_components;

			if ( m_numChannels != 1 && m_numChannels != 3 )
			{
				throw IOException( ( boost::format( "JPEGImageReader: Unsupported number of channels (%d) while opening file %s" ) % m_numChannels % m_bufferFileName ).str() );
			}

			if ( cinfo.out_color_space == JCS_GRAYSCALE )
			{
				assert( m_numChannels == 1 );
			}
			else if ( cinfo.out_color_space != JCS_RGB )
			{
				throw IOException( ( boost::format( "JPEGImageReader: Unsupported colorspace (%d) while opening file %s" ) % cinfo.out_color_space % m_bufferFileName ).str() );
			}
			/// \todo Add support for JCS_YCbCr encoding, and make sure that we add a parameter that
			/// species whether we should rescale values 0-255 to 16-235 (Y) and 16-239 (Cb/Cr) - default
			/// should be true. See http://www.fourcc.org/fccyvrgb.php for further info.

			/// Create buffer
			int rowStride = cinfo.output_width * cinfo.output_components;
			m_buffer.resize( rowStride * cinfo.output_height, 0 );
			;
			m_bufferWidth = cinfo.output_width;
			m_bufferHeight = cinfo.output_height;

			/// Read scanlines one at a time.
			while (cinfo.output_scanline < cinfo.output_height)
			{
				unsigned char *rowPointer[1] = { &m_buffer[0] + rowStride * cinfo.output_scanline };
				jpeg_read_scanlines( &cinfo, rowPointer, 1 );
			}

			/// Finish decompression
			jpeg_finish_decompress( &cinfo );
			jpeg_destroy_decompress( &cinfo );
		}
		catch ( Exception &e )
		{
			jpeg_destroy_decompress( &cinfo );

			throw;
		}
		catch ( std::exception &e )
		{
			jpeg_destroy_decompress( &cinfo );

			throw IOException( ( boost::format( "JPEGImageReader : %s" ) % e.what() ).str() );
		}
		catch ( ... )
		{
			jpeg_destroy_decompress( &cinfo );

			throw IOException( "JPEGImageReader: Unexpected error" );
		}

		fclose( inFile );
	}
	catch (...)
	{
		if ( inFile )
		{
			fclose( inFile );
		}

		if ( throwOnFailure )
		{
			throw;
		}
		else
		{
			return false;
		}
	}

	return true;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <catch2/catch.hpp>

#include "libslic3r/TriangleMesh.hpp"

using namespace Slic3r;

TEST_CASE("Split empty mesh", "[its_split][its]") {
    using namespace Slic3r;

    indexed_triangle_set its;

    std::vector<indexed_triangle_set> res = its_split(its);

    REQUIRE(res.empty());
}

TEST_CASE("Split simple mesh consisting of one part", "[its_split][its]") {
    using namespace Slic3r;

    auto cube = its_make_cube(10., 10., 10.);

    std::vector<indexed_triangle_set> res = its_split(cube);

    REQUIRE(res.size() == 1);
    REQUIRE(res.front().indices.size() == cube.indices.size());
    REQUIRE(res.front().vertices.size() == cube.vertices.size());
}

void debug_write_obj(const std::vector<indexed_triangle_set> &res, const std::string &name)
{
#ifndef NDEBUG
    size_t part_idx = 0;
    for (auto &part_its : res) {
        its_write_obj(part_its, (name + std::to_string(part_idx++) + ".obj").c_str());
    }
#endif
}

TEST_CASE("Split two non-watertight mesh", "[its_split][its]") {
    using namespace Slic3r;

    auto cube1 = its_make_cube(10., 10., 10.);
    cube1.indices.pop_back();
    auto cube2 = cube1;

    its_transform(cube1, identity3f().translate(Vec3f{-5.f, 0.f, 0.f}));
    its_transform(cube2, identity3f().translate(Vec3f{5.f, 0.f, 0.f}));

    its_merge(cube1, cube2);

    std::vector<indexed_triangle_set> res = its_split(cube1);

    REQUIRE(res.size() == 2);
    REQUIRE(res[0].indices.size() == res[1].indices.size());
    REQUIRE(res[0].indices.size() == cube2.indices.size());
    REQUIRE(res[0].vertices.size() == res[1].vertices.size());
    REQUIRE(res[0].vertices.size() == cube2.vertices.size());

    debug_write_obj(res, "parts_non_watertight");
}

TEST_CASE("Split non-manifold mesh", "[its_split][its]") {
    using namespace Slic3r;

    auto cube = its_make_cube(10., 10., 10.), cube_low = cube;

    its_transform(cube_low, identity3f().translate(Vec3f{10.f, 10.f, 10.f}));
    its_merge(cube, cube_low);
    its_merge_vertices(cube);

    std::vector<indexed_triangle_set> res = its_split(cube);

    REQUIRE(res.size() == 2);
    REQUIRE(res[0].indices.size() == res[1].indices.size());
    REQUIRE(res[0].indices.size() == cube_low.indices.size());
    REQUIRE(res[0].vertices.size() == res[1].vertices.size());
    REQUIRE(res[0].vertices.size() == cube_low.vertices.size());

    debug_write_obj(res, "cubes_non_manifold");
}

TEST_CASE("Split two watertight meshes", "[its_split][its]") {
    using namespace Slic3r;

    auto sphere1 = its_make_sphere(10., 2 * PI / 200.), sphere2 = sphere1;

    its_transform(sphere1, identity3f().translate(Vec3f{-5.f, 0.f, 0.f}));
    its_transform(sphere2, identity3f().translate(Vec3f{5.f, 0.f, 0.f}));

    its_merge(sphere1, sphere2);

    std::vector<indexed_triangle_set> res = its_split(sphere1);

    REQUIRE(res.size() == 2);
    REQUIRE(res[0].indices.size() == res[1].indices.size());
    REQUIRE(res[0].indices.size() == sphere2.indices.size());
    REQUIRE(res[0].vertices.size() == res[1].vertices.size());
    REQUIRE(res[0].vertices.size() == sphere2.vertices.size());

    debug_write_obj(res, "parts_watertight");
}

#include <libslic3r/QuadricEdgeCollapse.hpp>
TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]")
{
    indexed_triangle_set its;
    its.vertices = {Vec3f(-1.f, 0.f, 0.f), Vec3f(0.f, 1.f, 0.f),
                    Vec3f(1.f, 0.f, 0.f), Vec3f(0.f, 0.f, 1.f),
                    // vertex to be removed
                    Vec3f(0.9f, .1f, -.1f)};
    its.indices  = {Vec3i(1, 0, 3), Vec3i(2, 1, 3), Vec3i(0, 2, 3),
                   Vec3i(0, 1, 4), Vec3i(1, 2, 4), Vec3i(2, 0, 4)};
    // edge to remove is between vertices 2 and 4 on trinagles 4 and 5

    indexed_triangle_set its_ = its; // copy
    // its_write_obj(its, "tetrhedron_in.obj");
    size_t wanted_count = its.indices.size() - 1;
    CHECK(its_quadric_edge_collapse(its, wanted_count));
    // its_write_obj(its, "tetrhedron_out.obj");
    CHECK(its.indices.size() == 4);
    CHECK(its.vertices.size() == 4);

    for (size_t i = 0; i < 3; i++) {
        CHECK(its.indices[i] == its_.indices[i]);
    }

    for (size_t i = 0; i < 4; i++) {
        if (i == 2) continue;
        CHECK(its.vertices[i] == its_.vertices[i]);
    }

    const Vec3f &v = its.vertices[2]; // new vertex
    const Vec3f &v2 = its_.vertices[2]; // moved vertex
    const Vec3f &v4 = its_.vertices[4]; // removed vertex
    for (size_t i = 0; i < 3; i++) {
        bool is_between = (v[i] < v4[i] && v[i] > v2[i]) ||
                          (v[i] > v4[i] && v[i] < v2[i]);
        CHECK(is_between);
    }
}

#include "test_utils.hpp"
TEST_CASE("Symplify mesh by Quadric edge collapse to 5%", "[its]")
{
    TriangleMesh mesh = load_model("frog_legs.obj");
    double original_volume = its_volume(mesh.its);
    size_t wanted_count = mesh.its.indices.size() * 0.05;
    REQUIRE_FALSE(mesh.empty());
    indexed_triangle_set its = mesh.its; // copy
    its_quadric_edge_collapse(its, wanted_count);
    // its_write_obj(its, "frog_legs_qec.obj");
    CHECK(its.indices.size() <= wanted_count);
    double volume = its_volume(its);
    CHECK(fabs(original_volume - volume) < 30.);
}<commit_msg>Extend test with checking simplified model distance to original model<commit_after>#include <iostream>
#include <fstream>
#include <catch2/catch.hpp>

#include "libslic3r/TriangleMesh.hpp"

using namespace Slic3r;

TEST_CASE("Split empty mesh", "[its_split][its]") {
    using namespace Slic3r;

    indexed_triangle_set its;

    std::vector<indexed_triangle_set> res = its_split(its);

    REQUIRE(res.empty());
}

TEST_CASE("Split simple mesh consisting of one part", "[its_split][its]") {
    using namespace Slic3r;

    auto cube = its_make_cube(10., 10., 10.);

    std::vector<indexed_triangle_set> res = its_split(cube);

    REQUIRE(res.size() == 1);
    REQUIRE(res.front().indices.size() == cube.indices.size());
    REQUIRE(res.front().vertices.size() == cube.vertices.size());
}

void debug_write_obj(const std::vector<indexed_triangle_set> &res, const std::string &name)
{
#ifndef NDEBUG
    size_t part_idx = 0;
    for (auto &part_its : res) {
        its_write_obj(part_its, (name + std::to_string(part_idx++) + ".obj").c_str());
    }
#endif
}

TEST_CASE("Split two non-watertight mesh", "[its_split][its]") {
    using namespace Slic3r;

    auto cube1 = its_make_cube(10., 10., 10.);
    cube1.indices.pop_back();
    auto cube2 = cube1;

    its_transform(cube1, identity3f().translate(Vec3f{-5.f, 0.f, 0.f}));
    its_transform(cube2, identity3f().translate(Vec3f{5.f, 0.f, 0.f}));

    its_merge(cube1, cube2);

    std::vector<indexed_triangle_set> res = its_split(cube1);

    REQUIRE(res.size() == 2);
    REQUIRE(res[0].indices.size() == res[1].indices.size());
    REQUIRE(res[0].indices.size() == cube2.indices.size());
    REQUIRE(res[0].vertices.size() == res[1].vertices.size());
    REQUIRE(res[0].vertices.size() == cube2.vertices.size());

    debug_write_obj(res, "parts_non_watertight");
}

TEST_CASE("Split non-manifold mesh", "[its_split][its]") {
    using namespace Slic3r;

    auto cube = its_make_cube(10., 10., 10.), cube_low = cube;

    its_transform(cube_low, identity3f().translate(Vec3f{10.f, 10.f, 10.f}));
    its_merge(cube, cube_low);
    its_merge_vertices(cube);

    std::vector<indexed_triangle_set> res = its_split(cube);

    REQUIRE(res.size() == 2);
    REQUIRE(res[0].indices.size() == res[1].indices.size());
    REQUIRE(res[0].indices.size() == cube_low.indices.size());
    REQUIRE(res[0].vertices.size() == res[1].vertices.size());
    REQUIRE(res[0].vertices.size() == cube_low.vertices.size());

    debug_write_obj(res, "cubes_non_manifold");
}

TEST_CASE("Split two watertight meshes", "[its_split][its]") {
    using namespace Slic3r;

    auto sphere1 = its_make_sphere(10., 2 * PI / 200.), sphere2 = sphere1;

    its_transform(sphere1, identity3f().translate(Vec3f{-5.f, 0.f, 0.f}));
    its_transform(sphere2, identity3f().translate(Vec3f{5.f, 0.f, 0.f}));

    its_merge(sphere1, sphere2);

    std::vector<indexed_triangle_set> res = its_split(sphere1);

    REQUIRE(res.size() == 2);
    REQUIRE(res[0].indices.size() == res[1].indices.size());
    REQUIRE(res[0].indices.size() == sphere2.indices.size());
    REQUIRE(res[0].vertices.size() == res[1].vertices.size());
    REQUIRE(res[0].vertices.size() == sphere2.vertices.size());

    debug_write_obj(res, "parts_watertight");
}

#include <libslic3r/QuadricEdgeCollapse.hpp>
static float triangle_area(const Vec3f &v0, const Vec3f &v1, const Vec3f &v2)
{
    Vec3f ab = v1 - v0;
    Vec3f ac = v2 - v0;
    return ab.cross(ac).norm() / 2.f;
}

static float triangle_area(const Vec3crd &triangle_inices, const std::vector<Vec3f> &vertices)
{
    return triangle_area(vertices[triangle_inices[0]],
                         vertices[triangle_inices[1]],
                         vertices[triangle_inices[2]]);
}

static std::mt19937 create_random_generator() {
    std::random_device rd;
    std::mt19937 gen(rd());
    return gen;
}

std::vector<Vec3f> its_sample_surface(const indexed_triangle_set &its,
                                      double        sample_per_mm2,
                                      std::mt19937 &random_generator = create_random_generator())
{
    std::vector<Vec3f> samples;
    std::uniform_real_distribution<float> rand01(0.f, 1.f);
    for (const auto &triangle_indices : its.indices) {
        float area = triangle_area(triangle_indices, its.vertices);
        float countf;
        float fractional = std::modf(area * sample_per_mm2, &countf);
        int count = static_cast<int>(countf);

        float generate = rand01(random_generator);
        if (generate < fractional) ++count;
        if (count == 0) continue;

        const Vec3f &v0 = its.vertices[triangle_indices[0]];
        const Vec3f &v1 = its.vertices[triangle_indices[1]];
        const Vec3f &v2 = its.vertices[triangle_indices[2]];
        for (int c = 0; c < count; c++) {
            // barycentric coordinate
            Vec3f b;
            b[0] = rand01(random_generator);
            b[1] = rand01(random_generator);
            if ((b[0] + b[1]) > 1.f) {
                b[0] = 1.f - b[0];
                b[1] = 1.f - b[1];
            }
            b[2] = 1.f - b[0] - b[1];
            Vec3f pos;
            for (int i = 0; i < 3; i++) {
                pos[i] = b[0] * v0[i] + b[1] * v1[i] + b[2] * v2[i];
            }
            samples.push_back(pos);
        }
    }
    return samples;
}

#include "libslic3r/AABBTreeIndirect.hpp"

// return Average abs distance to original
float compare(const indexed_triangle_set &original,
               const indexed_triangle_set &simplified,
               double sample_per_mm2)
{
    // create ABBTree
    auto tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(
        original.vertices, original.indices);

    unsigned int init = 0;
    std::mt19937 rnd(init);
    auto samples = its_sample_surface(simplified, sample_per_mm2, rnd);

    float sumDistance = 0;
    for (const Vec3f &sample : samples) {
        size_t hit_idx;
        Vec3f  hit_point;
        float distance2 = AABBTreeIndirect::squared_distance_to_indexed_triangle_set(
            original.vertices, original.indices, tree, sample, hit_idx,
            hit_point);
        sumDistance += sqrt(distance2);
    }
    return sumDistance / samples.size();
}

TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]")
{
    indexed_triangle_set its;
    its.vertices = {Vec3f(-1.f, 0.f, 0.f), Vec3f(0.f, 1.f, 0.f),
                    Vec3f(1.f, 0.f, 0.f), Vec3f(0.f, 0.f, 1.f),
                    // vertex to be removed
                    Vec3f(0.9f, .1f, -.1f)};
    its.indices  = {Vec3i(1, 0, 3), Vec3i(2, 1, 3), Vec3i(0, 2, 3),
                   Vec3i(0, 1, 4), Vec3i(1, 2, 4), Vec3i(2, 0, 4)};
    // edge to remove is between vertices 2 and 4 on trinagles 4 and 5

    indexed_triangle_set its_ = its; // copy
    // its_write_obj(its, "tetrhedron_in.obj");
    size_t wanted_count = its.indices.size() - 1;
    CHECK(its_quadric_edge_collapse(its, wanted_count));
    // its_write_obj(its, "tetrhedron_out.obj");
    CHECK(its.indices.size() == 4);
    CHECK(its.vertices.size() == 4);

    for (size_t i = 0; i < 3; i++) {
        CHECK(its.indices[i] == its_.indices[i]);
    }

    for (size_t i = 0; i < 4; i++) {
        if (i == 2) continue;
        CHECK(its.vertices[i] == its_.vertices[i]);
    }

    const Vec3f &v = its.vertices[2]; // new vertex
    const Vec3f &v2 = its_.vertices[2]; // moved vertex
    const Vec3f &v4 = its_.vertices[4]; // removed vertex
    for (size_t i = 0; i < 3; i++) {
        bool is_between = (v[i] < v4[i] && v[i] > v2[i]) ||
                          (v[i] > v4[i] && v[i] < v2[i]);
        CHECK(is_between);
    }
    float avg_distance = compare(its_, its, 10);
    CHECK(avg_distance < 8e-3f);
}

#include "test_utils.hpp"
TEST_CASE("Symplify mesh by Quadric edge collapse to 5%", "[its]")
{
    TriangleMesh mesh = load_model("frog_legs.obj");
    double original_volume = its_volume(mesh.its);
    size_t wanted_count = mesh.its.indices.size() * 0.05;
    REQUIRE_FALSE(mesh.empty());
    indexed_triangle_set its = mesh.its; // copy
    its_quadric_edge_collapse(its, wanted_count);
    // its_write_obj(its, "frog_legs_qec.obj");
    CHECK(its.indices.size() <= wanted_count);
    double volume = its_volume(its);
    CHECK(fabs(original_volume - volume) < 30.);

    float avg_distance = compare(mesh.its, its, 10);
    CHECK(avg_distance < 0.021f); // 0.02022 | 0.0199614074
}<|endoftext|>


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

#include "content/browser/webui/web_ui.h"

#include "base/command_line.h"
#include "base/json/json_writer.h"
#include "base/stl_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "content/browser/child_process_security_policy.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/tab_contents_view.h"
#include "content/browser/webui/generic_handler.h"
#include "content/common/view_messages.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/content_switches.h"

using content::WebContents;
using content::WebUIController;
using content::WebUIMessageHandler;

// static
string16 WebUI::GetJavascriptCall(
    const std::string& function_name,
    const std::vector<const Value*>& arg_list) {
  string16 parameters;
  std::string json;
  for (size_t i = 0; i < arg_list.size(); ++i) {
    if (i > 0)
      parameters += char16(',');

    base::JSONWriter::Write(arg_list[i], false, &json);
    parameters += UTF8ToUTF16(json);
  }
  return ASCIIToUTF16(function_name) +
      char16('(') + parameters + char16(')') + char16(';');
}

WebUI::WebUI(WebContents* contents)
    : focus_location_bar_by_default_(false),
      should_hide_url_(false),
      link_transition_type_(content::PAGE_TRANSITION_LINK),
      bindings_(content::BINDINGS_POLICY_WEB_UI),
      register_callback_overwrites_(false),
      web_contents_(contents) {
  DCHECK(contents);
  AddMessageHandler(new GenericHandler());
}

WebUI::~WebUI() {
  // Delete the controller first, since it may also be keeping a pointer to some
  // of the handlers and can call them at destruction.
  controller_.reset();
  STLDeleteContainerPointers(handlers_.begin(), handlers_.end());
}

// WebUI, public: -------------------------------------------------------------

const WebUI::TypeID WebUI::kNoWebUI = NULL;

bool WebUI::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(WebUI, message)
    IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void WebUI::OnWebUISend(const GURL& source_url,
                        const std::string& message,
                        const ListValue& args) {
  if (!ChildProcessSecurityPolicy::GetInstance()->
          HasWebUIBindings(web_contents_->GetRenderProcessHost()->GetID())) {
    NOTREACHED() << "Blocked unauthorized use of WebUIBindings.";
    return;
  }

  if (controller_->OverrideHandleWebUIMessage(source_url, message,args))
    return;

  // Look up the callback for this message.
  MessageCallbackMap::const_iterator callback =
      message_callbacks_.find(message);
  if (callback != message_callbacks_.end()) {
    // Forward this message and content on.
    callback->second.Run(&args);
  }
}

void WebUI::RenderViewCreated(RenderViewHost* render_view_host) {
  controller_->RenderViewCreated(render_view_host);

  // Do not attempt to set the toolkit property if WebUI is not enabled, e.g.,
  // the bookmarks manager page.
  if (!(bindings_ & content::BINDINGS_POLICY_WEB_UI))
    return;

#if defined(TOOLKIT_VIEWS)
  render_view_host->SetWebUIProperty("toolkit", "views");
#elif defined(TOOLKIT_GTK)
  render_view_host->SetWebUIProperty("toolkit", "GTK");
#endif  // defined(TOOLKIT_VIEWS)

  // Let the WebUI know that we're looking for UI that's optimized for touch
  // input.
  // TODO(rbyers) Figure out the right model for enabling touch-optimized UI
  // (http://crbug.com/105380).
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTouchOptimizedUI))
    render_view_host->SetWebUIProperty("touchOptimized", "true");
}

WebContents* WebUI::GetWebContents() const {
  return web_contents_;
}

bool WebUI::ShouldHideFavicon() const {
  return hide_favicon_;
}

void WebUI::HideFavicon() {
  hide_favicon_ = true;
}

bool WebUI::ShouldFocusLocationBarByDefault() const {
  return focus_location_bar_by_default_;
}

void WebUI::FocusLocationBarByDefault() {
  focus_location_bar_by_default_ = true;
}

bool WebUI::ShouldHideURL() const {
  return should_hide_url_;
}

void WebUI::HideURL() {
  should_hide_url_ = true;
}

const string16& WebUI::GetOverriddenTitle() const {
  return overridden_title_;
}

void WebUI::OverrideTitle(const string16& title) {
  overridden_title_ = title;
}

content::PageTransition WebUI::GetLinkTransitionType() const {
  return link_transition_type_;
}

void WebUI::SetLinkTransitionType(content::PageTransition type) {
  link_transition_type_ = type;
}

int WebUI::GetBindings() const {
  return bindings_;
}

void WebUI::SetBindings(int bindings) {
  bindings_ = bindings;
}

void WebUI::SetFrameXPath(const std::string& xpath) {
  frame_xpath_ = xpath;
}

WebUIController* WebUI::GetController() const {
  return controller_.get();
}

void WebUI::SetController(WebUIController* controller) {
  controller_.reset(controller);
}

void WebUI::CallJavascriptFunction(const std::string& function_name) {
  DCHECK(IsStringASCII(function_name));
  string16 javascript = ASCIIToUTF16(function_name + "();");
  ExecuteJavascript(javascript);
}

void WebUI::CallJavascriptFunction(const std::string& function_name,
                                   const Value& arg) {
  DCHECK(IsStringASCII(function_name));
  std::vector<const Value*> args;
  args.push_back(&arg);
  ExecuteJavascript(WebUI::GetJavascriptCall(function_name, args));
}

void WebUI::CallJavascriptFunction(
    const std::string& function_name,
    const Value& arg1, const Value& arg2) {
  DCHECK(IsStringASCII(function_name));
  std::vector<const Value*> args;
  args.push_back(&arg1);
  args.push_back(&arg2);
  ExecuteJavascript(WebUI::GetJavascriptCall(function_name, args));
}

void WebUI::CallJavascriptFunction(
    const std::string& function_name,
    const Value& arg1, const Value& arg2, const Value& arg3) {
  DCHECK(IsStringASCII(function_name));
  std::vector<const Value*> args;
  args.push_back(&arg1);
  args.push_back(&arg2);
  args.push_back(&arg3);
  ExecuteJavascript(WebUI::GetJavascriptCall(function_name, args));
}

void WebUI::CallJavascriptFunction(
    const std::string& function_name,
    const Value& arg1,
    const Value& arg2,
    const Value& arg3,
    const Value& arg4) {
  DCHECK(IsStringASCII(function_name));
  std::vector<const Value*> args;
  args.push_back(&arg1);
  args.push_back(&arg2);
  args.push_back(&arg3);
  args.push_back(&arg4);
  ExecuteJavascript(WebUI::GetJavascriptCall(function_name, args));
}

void WebUI::CallJavascriptFunction(
    const std::string& function_name,
    const std::vector<const Value*>& args) {
  DCHECK(IsStringASCII(function_name));
  ExecuteJavascript(WebUI::GetJavascriptCall(function_name, args));
}

void WebUI::RegisterMessageCallback(const std::string &message,
                                    const MessageCallback& callback) {
  std::pair<MessageCallbackMap::iterator, bool> result =
      message_callbacks_.insert(std::make_pair(message, callback));

  // Overwrite preexisting message callback mappings.
  if (!result.second && register_callback_overwrites())
    result.first->second = callback;
}

// WebUI, protected: ----------------------------------------------------------

void WebUI::AddMessageHandler(WebUIMessageHandler* handler) {
  DCHECK(!handler->web_ui());
  handler->set_web_ui(this);
  handler->RegisterMessages();
  handlers_.push_back(handler);
}

void WebUI::ExecuteJavascript(const string16& javascript) {
  web_contents_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
      ASCIIToUTF16(frame_xpath_), javascript);
}
<commit_msg>Fix uninitalized varible in WebUI. I was going to remove this out of WebUI, then reverted that change but forgot to initialize it again.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/webui/web_ui.h"

#include "base/command_line.h"
#include "base/json/json_writer.h"
#include "base/stl_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "content/browser/child_process_security_policy.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/tab_contents_view.h"
#include "content/browser/webui/generic_handler.h"
#include "content/common/view_messages.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/content_switches.h"

using content::WebContents;
using content::WebUIController;
using content::WebUIMessageHandler;

// static
string16 WebUI::GetJavascriptCall(
    const std::string& function_name,
    const std::vector<const Value*>& arg_list) {
  string16 parameters;
  std::string json;
  for (size_t i = 0; i < arg_list.size(); ++i) {
    if (i > 0)
      parameters += char16(',');

    base::JSONWriter::Write(arg_list[i], false, &json);
    parameters += UTF8ToUTF16(json);
  }
  return ASCIIToUTF16(function_name) +
      char16('(') + parameters + char16(')') + char16(';');
}

WebUI::WebUI(WebContents* contents)
    : hide_favicon_(false),
      focus_location_bar_by_default_(false),
      should_hide_url_(false),
      link_transition_type_(content::PAGE_TRANSITION_LINK),
      bindings_(content::BINDINGS_POLICY_WEB_UI),
      register_callback_overwrites_(false),
      web_contents_(contents) {
  DCHECK(contents);
  AddMessageHandler(new GenericHandler());
}

WebUI::~WebUI() {
  // Delete the controller first, since it may also be keeping a pointer to some
  // of the handlers and can call them at destruction.
  controller_.reset();
  STLDeleteContainerPointers(handlers_.begin(), handlers_.end());
}

// WebUI, public: -------------------------------------------------------------

const WebUI::TypeID WebUI::kNoWebUI = NULL;

bool WebUI::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(WebUI, message)
    IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void WebUI::OnWebUISend(const GURL& source_url,
                        const std::string& message,
                        const ListValue& args) {
  if (!ChildProcessSecurityPolicy::GetInstance()->
          HasWebUIBindings(web_contents_->GetRenderProcessHost()->GetID())) {
    NOTREACHED() << "Blocked unauthorized use of WebUIBindings.";
    return;
  }

  if (controller_->OverrideHandleWebUIMessage(source_url, message,args))
    return;

  // Look up the callback for this message.
  MessageCallbackMap::const_iterator callback =
      message_callbacks_.find(message);
  if (callback != message_callbacks_.end()) {
    // Forward this message and content on.
    callback->second.Run(&args);
  }
}

void WebUI::RenderViewCreated(RenderViewHost* render_view_host) {
  controller_->RenderViewCreated(render_view_host);

  // Do not attempt to set the toolkit property if WebUI is not enabled, e.g.,
  // the bookmarks manager page.
  if (!(bindings_ & content::BINDINGS_POLICY_WEB_UI))
    return;

#if defined(TOOLKIT_VIEWS)
  render_view_host->SetWebUIProperty("toolkit", "views");
#elif defined(TOOLKIT_GTK)
  render_view_host->SetWebUIProperty("toolkit", "GTK");
#endif  // defined(TOOLKIT_VIEWS)

  // Let the WebUI know that we're looking for UI that's optimized for touch
  // input.
  // TODO(rbyers) Figure out the right model for enabling touch-optimized UI
  // (http://crbug.com/105380).
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTouchOptimizedUI))
    render_view_host->SetWebUIProperty("touchOptimized", "true");
}

WebContents* WebUI::GetWebContents() const {
  return web_contents_;
}

bool WebUI::ShouldHideFavicon() const {
  return hide_favicon_;
}

void WebUI::HideFavicon() {
  hide_favicon_ = true;
}

bool WebUI::ShouldFocusLocationBarByDefault() const {
  return focus_location_bar_by_default_;
}

void WebUI::FocusLocationBarByDefault() {
  focus_location_bar_by_default_ = true;
}

bool WebUI::ShouldHideURL() const {
  return should_hide_url_;
}

void WebUI::HideURL() {
  should_hide_url_ = true;
}

const string16& WebUI::GetOverriddenTitle() const {
  return overridden_title_;
}

void WebUI::OverrideTitle(const string16& title) {
  overridden_title_ = title;
}

content::PageTransition WebUI::GetLinkTransitionType() const {
  return link_transition_type_;
}

void WebUI::SetLinkTransitionType(content::PageTransition type) {
  link_transition_type_ = type;
}

int WebUI::GetBindings() const {
  return bindings_;
}

void WebUI::SetBindings(int bindings) {
  bindings_ = bindings;
}

void WebUI::SetFrameXPath(const std::string& xpath) {
  frame_xpath_ = xpath;
}

WebUIController* WebUI::GetController() const {
  return controller_.get();
}

void WebUI::SetController(WebUIController* controller) {
  controller_.reset(controller);
}

void WebUI::CallJavascriptFunction(const std::string& function_name) {
  DCHECK(IsStringASCII(function_name));
  string16 javascript = ASCIIToUTF16(function_name + "();");
  ExecuteJavascript(javascript);
}

void WebUI::CallJavascriptFunction(const std::string& function_name,
                                   const Value& arg) {
  DCHECK(IsStringASCII(function_name));
  std::vector<const Value*> args;
  args.push_back(&arg);
  ExecuteJavascript(WebUI::GetJavascriptCall(function_name, args));
}

void WebUI::CallJavascriptFunction(
    const std::string& function_name,
    const Value& arg1, const Value& arg2) {
  DCHECK(IsStringASCII(function_name));
  std::vector<const Value*> args;
  args.push_back(&arg1);
  args.push_back(&arg2);
  ExecuteJavascript(WebUI::GetJavascriptCall(function_name, args));
}

void WebUI::CallJavascriptFunction(
    const std::string& function_name,
    const Value& arg1, const Value& arg2, const Value& arg3) {
  DCHECK(IsStringASCII(function_name));
  std::vector<const Value*> args;
  args.push_back(&arg1);
  args.push_back(&arg2);
  args.push_back(&arg3);
  ExecuteJavascript(WebUI::GetJavascriptCall(function_name, args));
}

void WebUI::CallJavascriptFunction(
    const std::string& function_name,
    const Value& arg1,
    const Value& arg2,
    const Value& arg3,
    const Value& arg4) {
  DCHECK(IsStringASCII(function_name));
  std::vector<const Value*> args;
  args.push_back(&arg1);
  args.push_back(&arg2);
  args.push_back(&arg3);
  args.push_back(&arg4);
  ExecuteJavascript(WebUI::GetJavascriptCall(function_name, args));
}

void WebUI::CallJavascriptFunction(
    const std::string& function_name,
    const std::vector<const Value*>& args) {
  DCHECK(IsStringASCII(function_name));
  ExecuteJavascript(WebUI::GetJavascriptCall(function_name, args));
}

void WebUI::RegisterMessageCallback(const std::string &message,
                                    const MessageCallback& callback) {
  std::pair<MessageCallbackMap::iterator, bool> result =
      message_callbacks_.insert(std::make_pair(message, callback));

  // Overwrite preexisting message callback mappings.
  if (!result.second && register_callback_overwrites())
    result.first->second = callback;
}

// WebUI, protected: ----------------------------------------------------------

void WebUI::AddMessageHandler(WebUIMessageHandler* handler) {
  DCHECK(!handler->web_ui());
  handler->set_web_ui(this);
  handler->RegisterMessages();
  handlers_.push_back(handler);
}

void WebUI::ExecuteJavascript(const string16& javascript) {
  web_contents_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
      ASCIIToUTF16(frame_xpath_), javascript);
}
<|endoftext|>