<commit_before>/*
 * SuRealPMCB.cc
 *
 * Copyright (C) 2014 OpenCog Foundation
 *
 * Author: William Ma <https://github.com/williampma>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/nlp/types/atom_types.h>

#include "SuRealPMCB.h"

using namespace opencog::nlp;
using namespace opencog;

/**
 * The constructor for the PatternMatcherCallback.
 *
 * @param pAS    the corresponding AtomSpace
 * @param vars   the set of nodes that should be treated as variables
 */
SuRealPMCB::SuRealPMCB(AtomSpace* pAS, std::set<Handle> vars) : DefaultPatternMatchCB(pAS), m_vars(vars)
{

}

/**
 * Override the variable_match callback.
 *
 * Do the special checking for each variable matches.  Note that variables
 * in SuReal will not just be VariableNode, but any nodes with an actual word
 * (eg. (PredicateNode "runs"), (ConceptNode "dog@1324-12213"), etc).
 *
 * For each variable and its potential solution, the corresponding WordNode
 * will be located.  Then we following the WordNode to find LgWordCset to get
 * the LG dictionary entries.  If the two words have identical LG entries,
 * then the two words matches.  Just one pair of LG entries need to match even
 * if a word has multiple entries.
 *
 * @param hPat    the variable, a node extracted from the original query
 * @param hSoln   the potential mapping
 * @return        true if solution is rejected, false if accepted
 */
bool SuRealPMCB::variable_match(Handle &hPat, Handle &hSoln)
{
    logger().debug("[SuReal] In variable_match, looking at %s", hSoln->toShortString().c_str());

    // reject if the solution is not of the same type
    if (hPat->getType() != hSoln->getType())
        return true;

    // VariableNode can be matched to any VariableNode
    if (hPat->getType() == VARIABLE_NODE)
        return true;

    std::string sPat = _as->getName(hPat);
    std::string sPatWord = sPat.substr(0, sPat.find_first_of('@'));
    std::string sSoln = _as->getName(hSoln);
    std::string sSolnWord = sSoln.substr(0, sSoln.find_first_of('@'));

    // get the WordNode associated with the word (extracted from "word@1234" convention)
    Handle hPatWordNode = _as->getHandle(WORD_NODE, sPatWord);
    Handle hSolnWordNode = _as->getHandle(WORD_NODE, sSolnWord);

    // no WordNode? try NumberNode
    if (hSolnWordNode == Handle::UNDEFINED)
    {
        hPatWordNode = _as->getHandle(NUMBER_NODE, sPatWord);
        hSolnWordNode = _as->getHandle(NUMBER_NODE, sSolnWord);

        // no NumberNode neither
        if (hSolnWordNode == Handle::UNDEFINED)
            return true;
    }

    // get the neighbor of each WordNode within LgWordCset
    HandleSeq qPatSet =_as->getNeighbors(hPatWordNode, false, true, LG_WORD_CSET, false);
    HandleSeq qSolnSet = _as->getNeighbors(hSolnWordNode, false, true, LG_WORD_CSET, false);

    // check the HandleSeq to see if there is any pair that is equal (common LG entry)
    std::sort(qPatSet.begin(), qPatSet.end());
    std::sort(qSolnSet.begin(), qSolnSet.end());

    HandleSeq qItrsect;
    std::set_intersection(qPatSet.begin(), qPatSet.end(), qSolnSet.begin(), qSolnSet.end(), std::back_inserter(qItrsect));

    // if there's no common LG dictionary rules, then the two words do not match
    if (qItrsect.empty())
        return true;

    return false;
}

/**
 * Override the clause_match callback.
 *
 * Reject a clause match if the matched link is not in a SetLink linked to an
 * InterpretationNode.  The reason of doing it here instead of earlier in
 * link_match() is because it is possible a SetLink is used for other purpose
 * as part of R2L's output.
 *
 * @param pattrn_link_h   the matched clause, extracted from the input SetLink
 * @param grnd_link_h     the corresponding grounding to be checked
 * @return                true if rejected, false if accepted
 */
bool SuRealPMCB::clause_match(Handle &pattrn_link_h, Handle &grnd_link_h)
{
    logger().debug("[SuReal] In clause_match, looking at %s", grnd_link_h->toShortString().c_str());

    HandleSeq qISet = _as->getIncoming(grnd_link_h);

    // keep only SetLink, and check if any of the SetLink has an InterpretationNode as neightbor
    qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& h) { return h->getType() != SET_LINK; }), qISet.end());

    // helper lambda function to check for linkage to an InterpretationNode, given SetLink
    auto hasInterpretation = [this](Handle& h)
    {
        HandleSeq qN = _as->getNeighbors(h, true, false, REFERENCE_LINK, false);
        return std::any_of(qN.begin(), qN.end(), [](Handle& hn) { return hn->getType() == INTERPRETATION_NODE; });
    };

    // reject match (ie. return true) if there is no InterpretationNode
    return not std::any_of(qISet.begin(), qISet.end(), hasInterpretation);
}

/**
 * Implement the grounding method.
 *
 * Check all matched clauses to see if they are all within the same SetLink
 * linking to the same InterpretationNode.  If so, store the solution and try
 * to find more.
 *
 * @param var_soln   the variable & links mapping
 * @param pred_soln  the clause mapping
 * @return           always return false to search for more solutions
 */
bool SuRealPMCB::grounding(const std::map<Handle, Handle> &var_soln, const std::map<Handle, Handle> &pred_soln)
{
    logger().debug("[SuReal] grounding a solution");

    auto getInterpretation = [this](const Handle& h)
    {
        HandleSeq qISet = _as->getIncoming(h);
        qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& h) { return h->getType() != SET_LINK; }), qISet.end());

        HandleSeq results;

        for (auto& hSetLink : qISet)
        {
            HandleSeq qN  = _as->getNeighbors(hSetLink, true, false, REFERENCE_LINK, false);
            qN.erase(std::remove_if(qN.begin(), qN.end(), [](Handle& h) { return h->getType() != INTERPRETATION_NODE; }), qN.end());

            results.insert(results.end(), qN.begin(), qN.end());
        }

        return results;
    };

    HandleSeq qItprNode = getInterpretation(pred_soln.begin()->second);
    std::sort(qItprNode.begin(), qItprNode.end());

    for (std::map<Handle, Handle>::const_iterator it = ++pred_soln.begin(); it != pred_soln.end(); ++it)
    {
        HandleSeq thisSeq = getInterpretation(it->second);
        std::sort(thisSeq.begin(), thisSeq.end());

        HandleSeq overlapSeq;
        std::set_intersection(qItprNode.begin(), qItprNode.end(), thisSeq.begin(), thisSeq.end(), std::back_inserter(overlapSeq));

        qItprNode = overlapSeq;
    }

    // no common InterpretationNode, ignore this grounding
    if (qItprNode.empty())
        return false;

    // shrink var_soln to only contain solution for the variables
    std::map<Handle, Handle> shrinked_soln;

    for (const auto& kv : var_soln)
    {
        if (m_vars.count(kv.first) == 0)
            continue;

        shrinked_soln[kv.first] = kv.second;
    }

    // store the solution; all common InterpretationNode are solutions for this
    // grounding, so store the solution for each InterpretationNode
    for (auto n : qItprNode)
        m_results[n] = shrinked_soln;

    return false;
}

/**
 * Implement the perform_search method.
 *
 * Similar to DefaultPatternMatcherCB::perform_search, in which we start search
 * by looking at the thinnest clause with constants.  However, since most clauses
 * for SuReal will have 0 constants, most searches will require looking at all
 * the links.  This implementation improves that by looking at links within a
 * SetLink within a ReferenceLink with a InterpretationNode neightbor, thus
 * limiting the search space.
 *
 * @param pPME       pointer to the PatternMatchEngine
 * @param vars       a set of nodes that are variables
 * @param clauses    the clauses for the query
 * @param negations  the negative clauses
 */
void SuRealPMCB::perform_search(PatternMatchEngine* pPME, std::set<Handle>& vars, HandleSeq& clauses, HandleSeq& negations)
{
    size_t bestClauseIndex;
    Handle bestClause, bestSubClause, bestSubNode;

    // find the thinnest clause with constants
    bestSubNode = find_thinnest(clauses, bestSubClause, bestClauseIndex);

    if (bestSubNode != Handle::UNDEFINED && !vars.empty())
    {
        bestClause = clauses[bestClauseIndex];

        logger().debug("[SuReal] Search start node: %s", bestSubNode->toShortString().c_str());
        logger().debug("[SuReal] Start pred is: %s", bestSubClause->toShortString().c_str());

        IncomingSet iset = get_incoming_set(bestSubNode);

        for (auto& l : iset)
        {
            Handle h(l);
            logger().debug("[SuReal] Loop candidate: %s", h->toShortString().c_str());

            if (pPME->do_candidate(bestClause, bestSubClause, h))
                break;
        }

        return;
    }

    bestClause = clauses[0];

    logger().debug("[SuReal] Start pred is: %s", bestClause->toShortString().c_str());

    // helper for checking for InterpretationNode
    auto hasNoInterpretation = [this](Handle& h)
    {
        HandleSeq qISet = _as->getIncoming(h);
        qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& hl) { return hl->getType() != SET_LINK; }), qISet.end());

        auto hasNode = [this](Handle& hl)
        {
            HandleSeq qN = _as->getNeighbors(hl, true, false, REFERENCE_LINK, false);
            return std::any_of(qN.begin(), qN.end(), [](Handle& hn) { return hn->getType() == INTERPRETATION_NODE; });
        };

        return not std::any_of(qISet.begin(), qISet.end(), hasNode);
    };

    // keep only links of the same type as bestClause and have linkage to InterpretationNode
    HandleSeq qCandidate;
    _as->getHandlesByType(std::back_inserter(qCandidate), bestClause->getType());
    qCandidate.erase(std::remove_if(qCandidate.begin(), qCandidate.end(), hasNoInterpretation), qCandidate.end());

    for (auto& c : qCandidate)
    {
        logger().debug("[SuReal] Loop candidate: %s", c->toShortString().c_str());

        if (pPME->do_candidate(bestClause, bestClause, c))
            break;
    }
}

/**
 * Override the find_starter method in DefaultPatternMatchCB.
 *
 * Override find_starter so that it will not treat VariableNode variables,
 * but instead compare against the variable list.
 *
 * @param h       same as DefaultPatternMatchCB::find_starter
 * @param depth   same as DefaultPatternMatchCB::find_starter
 * @param start   same as DefaultPatternMatchCB::find_starter
 * @param width   same as DefaultPatternMatchCB::find_starter
 * @return        same as DefaultPatternMatchCB::find_starter but change
 *                the result if is a variable
 */
Handle SuRealPMCB::find_starter(Handle h, size_t& depth, Handle& start, size_t& width)
{
    Handle rh = DefaultPatternMatchCB::find_starter(h, depth, start, width);

    // if the non-VariableNode is actually a variable
    if (m_vars.count(rh) == 1)
        return Handle::UNDEFINED;

    return rh;
}

<commit_msg>Added missing InterpretationNode check + some comments<commit_after>/*
 * SuRealPMCB.cc
 *
 * Copyright (C) 2014 OpenCog Foundation
 *
 * Author: William Ma <https://github.com/williampma>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/nlp/types/atom_types.h>

#include "SuRealPMCB.h"

using namespace opencog::nlp;
using namespace opencog;

/**
 * The constructor for the PatternMatcherCallback.
 *
 * @param pAS    the corresponding AtomSpace
 * @param vars   the set of nodes that should be treated as variables
 */
SuRealPMCB::SuRealPMCB(AtomSpace* pAS, std::set<Handle> vars) : DefaultPatternMatchCB(pAS), m_vars(vars)
{

}

/**
 * Override the variable_match callback.
 *
 * Do the special checking for each variable matches.  Note that variables
 * in SuReal will not just be VariableNode, but any nodes with an actual word
 * (eg. (PredicateNode "runs"), (ConceptNode "dog@1324-12213"), etc).
 *
 * For each variable and its potential solution, the corresponding WordNode
 * will be located.  Then we following the WordNode to find LgWordCset to get
 * the LG dictionary entries.  If the two words have identical LG entries,
 * then the two words matches.  Just one pair of LG entries need to match even
 * if a word has multiple entries.
 *
 * @param hPat    the variable, a node extracted from the original query
 * @param hSoln   the potential mapping
 * @return        true if solution is rejected, false if accepted
 */
bool SuRealPMCB::variable_match(Handle &hPat, Handle &hSoln)
{
    logger().debug("[SuReal] In variable_match, looking at %s", hSoln->toShortString().c_str());

    // reject if the solution is not of the same type
    if (hPat->getType() != hSoln->getType())
        return true;

    // VariableNode can be matched to any VariableNode, similarly for InterpretationNode
    if (hPat->getType() == VARIABLE_NODE || hPat->getType() == INTERPRETATION_NODE)
        return true;

    std::string sPat = _as->getName(hPat);
    std::string sPatWord = sPat.substr(0, sPat.find_first_of('@'));
    std::string sSoln = _as->getName(hSoln);
    std::string sSolnWord = sSoln.substr(0, sSoln.find_first_of('@'));

    // get the WordNode associated with the word (extracted from "word@1234" convention)
    Handle hPatWordNode = _as->getHandle(WORD_NODE, sPatWord);
    Handle hSolnWordNode = _as->getHandle(WORD_NODE, sSolnWord);

    // no WordNode? try NumberNode
    if (hSolnWordNode == Handle::UNDEFINED)
    {
        hPatWordNode = _as->getHandle(NUMBER_NODE, sPatWord);
        hSolnWordNode = _as->getHandle(NUMBER_NODE, sSolnWord);

        // no NumberNode neither
        if (hSolnWordNode == Handle::UNDEFINED)
            return true;
    }

    // get the neighbor of each WordNode within LgWordCset
    HandleSeq qPatSet =_as->getNeighbors(hPatWordNode, false, true, LG_WORD_CSET, false);
    HandleSeq qSolnSet = _as->getNeighbors(hSolnWordNode, false, true, LG_WORD_CSET, false);

    // check the HandleSeq to see if there is any pair that is equal (common LG entry)
    std::sort(qPatSet.begin(), qPatSet.end());
    std::sort(qSolnSet.begin(), qSolnSet.end());

    HandleSeq qItrsect;
    std::set_intersection(qPatSet.begin(), qPatSet.end(), qSolnSet.begin(), qSolnSet.end(), std::back_inserter(qItrsect));

    // if there's no common LG dictionary rules, then the two words do not match
    if (qItrsect.empty())
        return true;

    return false;
}

/**
 * Override the clause_match callback.
 *
 * Reject a clause match if the matched link is not in a SetLink linked to an
 * InterpretationNode.  The reason of doing it here instead of earlier in
 * link_match() is because it is possible a SetLink is used for other purpose
 * as part of R2L's output.
 *
 * @param pattrn_link_h   the matched clause, extracted from the input SetLink
 * @param grnd_link_h     the corresponding grounding to be checked
 * @return                true if rejected, false if accepted
 */
bool SuRealPMCB::clause_match(Handle &pattrn_link_h, Handle &grnd_link_h)
{
    logger().debug("[SuReal] In clause_match, looking at %s", grnd_link_h->toShortString().c_str());

    HandleSeq qISet = _as->getIncoming(grnd_link_h);

    // keep only SetLink, and check if any of the SetLink has an InterpretationNode as neightbor
    qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& h) { return h->getType() != SET_LINK; }), qISet.end());

    // helper lambda function to check for linkage to an InterpretationNode, given SetLink
    auto hasInterpretation = [this](Handle& h)
    {
        HandleSeq qN = _as->getNeighbors(h, true, false, REFERENCE_LINK, false);
        return std::any_of(qN.begin(), qN.end(), [](Handle& hn) { return hn->getType() == INTERPRETATION_NODE; });
    };

    // reject match (ie. return true) if there is no InterpretationNode
    return not std::any_of(qISet.begin(), qISet.end(), hasInterpretation);
}

/**
 * Implement the grounding method.
 *
 * Check all matched clauses to see if they are all within the same SetLink
 * linking to the same InterpretationNode.  If so, store the solution and try
 * to find more.
 *
 * @param var_soln   the variable & links mapping
 * @param pred_soln  the clause mapping
 * @return           always return false to search for more solutions
 */
bool SuRealPMCB::grounding(const std::map<Handle, Handle> &var_soln, const std::map<Handle, Handle> &pred_soln)
{
    logger().debug("[SuReal] grounding a solution");

    // helper to get the InterpretationNode
    auto getInterpretation = [this](const Handle& h)
    {
        HandleSeq qISet = _as->getIncoming(h);
        qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& h) { return h->getType() != SET_LINK; }), qISet.end());

        HandleSeq results;

        for (auto& hSetLink : qISet)
        {
            HandleSeq qN  = _as->getNeighbors(hSetLink, true, false, REFERENCE_LINK, false);
            qN.erase(std::remove_if(qN.begin(), qN.end(), [](Handle& h) { return h->getType() != INTERPRETATION_NODE; }), qN.end());

            results.insert(results.end(), qN.begin(), qN.end());
        }

        return results;
    };

    HandleSeq qItprNode = getInterpretation(pred_soln.begin()->second);
    std::sort(qItprNode.begin(), qItprNode.end());

    // try to find a common InterpretationNode to the solutions
    for (std::map<Handle, Handle>::const_iterator it = ++pred_soln.begin(); it != pred_soln.end(); ++it)
    {
        HandleSeq thisSeq = getInterpretation(it->second);
        std::sort(thisSeq.begin(), thisSeq.end());

        HandleSeq overlapSeq;
        std::set_intersection(qItprNode.begin(), qItprNode.end(), thisSeq.begin(), thisSeq.end(), std::back_inserter(overlapSeq));

        qItprNode = overlapSeq;
    }

    // no common InterpretationNode, ignore this grounding
    if (qItprNode.empty())
        return false;

    // shrink var_soln to only contain solution for the variables
    std::map<Handle, Handle> shrinked_soln;

    for (const auto& kv : var_soln)
    {
        if (m_vars.count(kv.first) == 0)
            continue;

        shrinked_soln[kv.first] = kv.second;
    }

    // store the solution; all common InterpretationNode are solutions for this
    // grounding, so store the solution for each InterpretationNode
    for (auto n : qItprNode)
        m_results[n] = shrinked_soln;

    return false;
}

/**
 * Implement the perform_search method.
 *
 * Similar to DefaultPatternMatcherCB::perform_search, in which we start search
 * by looking at the thinnest clause with constants.  However, since most clauses
 * for SuReal will have 0 constants, most searches will require looking at all
 * the links.  This implementation improves that by looking at links within a
 * SetLink within a ReferenceLink with a InterpretationNode neightbor, thus
 * limiting the search space.
 *
 * @param pPME       pointer to the PatternMatchEngine
 * @param vars       a set of nodes that are variables
 * @param clauses    the clauses for the query
 * @param negations  the negative clauses
 */
void SuRealPMCB::perform_search(PatternMatchEngine* pPME, std::set<Handle>& vars, HandleSeq& clauses, HandleSeq& negations)
{
    size_t bestClauseIndex;
    Handle bestClause, bestSubClause, bestSubNode;

    // find the thinnest clause with constants
    bestSubNode = find_thinnest(clauses, bestSubClause, bestClauseIndex);

    if (bestSubNode != Handle::UNDEFINED && !vars.empty())
    {
        bestClause = clauses[bestClauseIndex];

        logger().debug("[SuReal] Search start node: %s", bestSubNode->toShortString().c_str());
        logger().debug("[SuReal] Start pred is: %s", bestSubClause->toShortString().c_str());

        IncomingSet iset = get_incoming_set(bestSubNode);

        for (auto& l : iset)
        {
            Handle h(l);
            logger().debug("[SuReal] Loop candidate: %s", h->toShortString().c_str());

            if (pPME->do_candidate(bestClause, bestSubClause, h))
                break;
        }

        return;
    }

    // reaching here means no contants, so do some search space reduction here
    bestClause = clauses[0];

    logger().debug("[SuReal] Start pred is: %s", bestClause->toShortString().c_str());

    // helper for checking for InterpretationNode
    auto hasNoInterpretation = [this](Handle& h)
    {
        HandleSeq qISet = _as->getIncoming(h);
        qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& hl) { return hl->getType() != SET_LINK; }), qISet.end());

        auto hasNode = [this](Handle& hl)
        {
            HandleSeq qN = _as->getNeighbors(hl, true, false, REFERENCE_LINK, false);
            return std::any_of(qN.begin(), qN.end(), [](Handle& hn) { return hn->getType() == INTERPRETATION_NODE; });
        };

        return not std::any_of(qISet.begin(), qISet.end(), hasNode);
    };

    // keep only links of the same type as bestClause and have linkage to InterpretationNode
    HandleSeq qCandidate;
    _as->getHandlesByType(std::back_inserter(qCandidate), bestClause->getType());
    qCandidate.erase(std::remove_if(qCandidate.begin(), qCandidate.end(), hasNoInterpretation), qCandidate.end());

    for (auto& c : qCandidate)
    {
        logger().debug("[SuReal] Loop candidate: %s", c->toShortString().c_str());

        if (pPME->do_candidate(bestClause, bestClause, c))
            break;
    }
}

/**
 * Override the find_starter method in DefaultPatternMatchCB.
 *
 * Override find_starter so that it will not treat VariableNode variables,
 * but instead compare against the variable list.
 *
 * @param h       same as DefaultPatternMatchCB::find_starter
 * @param depth   same as DefaultPatternMatchCB::find_starter
 * @param start   same as DefaultPatternMatchCB::find_starter
 * @param width   same as DefaultPatternMatchCB::find_starter
 * @return        same as DefaultPatternMatchCB::find_starter but change
 *                the result if is a variable
 */
Handle SuRealPMCB::find_starter(Handle h, size_t& depth, Handle& start, size_t& width)
{
    Handle rh = DefaultPatternMatchCB::find_starter(h, depth, start, width);

    // if the non-VariableNode is actually a variable
    if (m_vars.count(rh) == 1)
        return Handle::UNDEFINED;

    return rh;
}

<|endoftext|>


<commit_before>// This file is part of CRAAM, a C++ library for solving plain
// and robust Markov decision processes.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#pragma once

#include "Action.hpp"

#include <utility>
#include <tuple>
#include <vector>
#include <stdexcept>
#include <limits>
#include <string>

#include "cpp11-range-master/range.hpp"

namespace craam {

using namespace std;

// **************************************************************************************
//  SA State (SA rectangular, also used for a regular MDP)
// **************************************************************************************

/**
State for sa-rectangular uncertainty (or no uncertainty) in an MDP

Actions within a state are sequentially labeled. That is, adding an action with an id = 3
will also create actions 0,1,2. These additional actions are marked as "invalid" state. This
means that they will not be used in computations and algorithms will simply skip over them.
Use `create_action` to make and action valid.

\tparam Type of action used in the state. This type determines the
    type of uncertainty set.
*/
template<class AType>
class SAState{
protected:
    /// list of actions
    vector<AType> actions;
    /// whether actions can be used in computation. If false, that means
    /// that they should not be used in algorithms or in computation.
    vector<bool> valid;

public:

    SAState() : actions(0), valid(0) {};

    /** Initializes state with actions and sets them all to valid */
    SAState(const vector<AType>& actions) : actions(actions), valid(actions.size(),true) { };

    /** Number of actions */
    size_t action_count() const { return actions.size();};

    /** Number of actions */
    size_t size() const { return action_count();};

    /**
    Creates an action given by actionid if it does not exists.
    Otherwise returns the existing one.

    All newly created actions with id < actionid are created as invalid
    (action.get_valid() = false). Action actionid is created as valid.
    */
    AType& create_action(long actionid){
        assert(actionid >= 0);

        // assumes that the default constructor makes the actions invalid
        if(actionid >= (long) actions.size()){
            actions.resize(actionid+1);
            valid.resize(actionid+1, false);
        }

        // set only the action that is being added as valid
        valid[actionid] = true;
        return actions[actionid];
    }

    /** Creates an action at the last position of the state */
    AType& create_action() {return create_action(actions.size());};

    /** Returns an existing action */
    const AType& get_action(long actionid) const
                {assert(actionid >= 0 && size_t(actionid) < action_count());
                 return actions[actionid];};

    /** Returns an existing action */
    const AType& operator[](long actionid) const {return get_action(actionid);}

    /** Returns an existing action */
    AType& get_action(long actionid)
                {assert(actionid >= 0 && size_t(actionid) < action_count());
                 return actions[actionid];};

    /** Returns an existing action */
    AType& operator[](long actionid) {return get_action(actionid);}

    /// Returns whether the actions is valid
    bool is_valid(long actionid) const {
        assert(actionid < long(valid.size()) && actionid >= 0);
        return valid[actionid];
    };

    /**
    Set action validity. A valid action can be used in computations. An
    invalid action is just a placeholder.
    */
    void set_valid(long actionid, bool value = true){
        assert(actionid < long(valid.size()) && actionid >= 0);
        valid[actionid] = value;
    };

    /** Returns set of all actions */
    const vector<AType>& get_actions() const {return actions;};

    /** True if the state is considered terminal (no actions). */
    bool is_terminal() const {return actions.empty();};

    /** Normalizes transition probabilities to sum to one. */
    void normalize(){
        for(AType& a : actions)
            a.normalize();
    }

    /** Checks whether the prescribed action and outcome are correct */
    bool is_action_correct(long aid, numvec nataction) const{
        if( (aid < 0) || ((size_t)aid >= actions.size()))
            return false;

        return actions[aid].is_nature_correct(nataction);
    }

   /** Checks whether the prescribed action correct */
    bool is_action_correct(long aid) const{
        if( (aid < 0) || ((size_t)aid >= actions.size()))
            return false;
        else
            return true;
    }

    /** Returns the mean reward following the action (and outcome). */
    prec_t mean_reward(long actionid, numvec nataction) const{
        if(is_terminal()) return 0;
        else return get_action(actionid).mean_reward(nataction);
    }

    /** Returns the mean reward following the action. */
    prec_t mean_reward(long actionid) const{
        if(is_terminal()) return 0;
        else return get_action(actionid).mean_reward();
    }

    /** Returns the mean transition probabilities following the action and outcome.
    This class assumes a deterministic policy of the decision maker and
    a randomized policy of nature.

    \param action Deterministic action of the decision maker
    \param nataction Randomized action of nature */
    Transition mean_transition(long action, numvec nataction) const{
        if(is_terminal()) return Transition();
        else return get_action(action).mean_transition(nataction);
    }

    /** Returns the mean transition probabilities following the action and outcome.

    \param action Deterministic action of decision maker */
    Transition mean_transition(long action) const{
        if(is_terminal()) return Transition();
        else return get_action(action).mean_transition();
    }

    /** Returns json representation of the state
    \param stateid Includes also state id*/
    string to_json(long stateid = -1) const{
        string result{"{"};
        result += "\"stateid\" : ";
        result += std::to_string(stateid);
        result += ",\"actions\" : [";
        for(auto ai : indices(actions)){
            const auto& a = actions[ai];
            result += a.to_json(ai);
            result += ",";
        }
        if(!actions.empty()) result.pop_back(); // remove last comma
        result += ("]}");
        return result;
    }
};

// **********************************************************************
// *********************    SPECIFIC STATE DEFINITIONS    ***************
// **********************************************************************

/// Regular MDP state with no outcomes
typedef SAState<RegularAction> RegularState;
/// State with uncertain outcomes with L1 constraints on the distribution
typedef SAState<WeightedOutcomeAction> WeightedRobustState;
}

/// helper functions
namespace internal{
    using namespace craam;

    /// checks state and policy with a policy of nature
    template<class SType>
    bool is_action_correct(const SType& state, long stateid, const std::pair<indvec,vector<numvec>>& policies){
        return state.is_action_correct(policies.first[stateid], policies.second[stateid]);
    }

    /// checks state that does not require nature
    template<class SType>
    bool is_action_correct(const SType& state, long stateid, const indvec& policy){
        return state.is_action_correct(policy[stateid]);
    }
}
<commit_msg>fix bug<commit_after>// This file is part of CRAAM, a C++ library for solving plain
// and robust Markov decision processes.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#pragma once

#include "Action.hpp"

#include <utility>
#include <tuple>
#include <vector>
#include <stdexcept>
#include <limits>
#include <string>

#include "cpp11-range-master/range.hpp"

namespace craam {

using namespace std;

// **************************************************************************************
//  SA State (SA rectangular, also used for a regular MDP)
// **************************************************************************************

/**
State for sa-rectangular uncertainty (or no uncertainty) in an MDP

Actions within a state are sequentially labeled. That is, adding an action with an id = 3
will also create actions 0,1,2. These additional actions are marked as "invalid" state. This
means that they will not be used in computations and algorithms will simply skip over them.
Use `create_action` to make and action valid.

\tparam Type of action used in the state. This type determines the
    type of uncertainty set.
*/
template<class AType>
class SAState{
protected:
    /// list of actions
    vector<AType> actions;
    /// whether actions can be used in computation. If false, that means
    /// that they should not be used in algorithms or in computation.
    vector<bool> valid;

public:

    SAState() : actions(0), valid(0) {};

    /** Initializes state with actions and sets them all to valid */
    SAState(const vector<AType>& actions) : actions(actions), valid(actions.size(),true) { };

    /** Number of actions */
    size_t action_count() const { return actions.size();};

    /** Number of actions */
    size_t size() const { return action_count();};

    /**
    Creates an action given by actionid if it does not exists.
    Otherwise returns the existing one.

    All newly created actions with id < actionid are created as invalid
    (action.get_valid() = false). Action actionid is created as valid.
    */
    AType& create_action(long actionid){
        assert(actionid >= 0);

        // assumes that the default constructor makes the actions invalid
        if(actionid >= (long) actions.size()){
            actions.resize(actionid+1);
            valid.resize(actionid+1, false);
        }

        // set only the action that is being added as valid
        valid[actionid] = true;
        return actions[actionid];
    }

    /** Creates an action at the last position of the state */
    AType& create_action() {return create_action(actions.size());};

    /** Returns an existing action */
    const AType& get_action(long actionid) const
                {assert(actionid >= 0 && size_t(actionid) < action_count());
                 return actions[actionid];};

    /** Returns an existing action */
    const AType& operator[](long actionid) const {return get_action(actionid);}

    /** Returns an existing action */
    AType& get_action(long actionid)
                {assert(actionid >= 0 && size_t(actionid) < action_count());
                 return actions[actionid];};

    /** Returns an existing action */
    AType& operator[](long actionid) {return get_action(actionid);}

    /// Returns whether the actions is valid
    bool is_valid(long actionid) const {
        assert(actionid < long(valid.size()) && actionid >= 0);
        return valid[actionid];
    };

    /**
    Set action validity. A valid action can be used in computations. An
    invalid action is just a placeholder.
    */
    void set_valid(long actionid, bool value = true){
        assert(actionid < long(valid.size()) && actionid >= 0);
        valid[actionid] = value;
    };

    /** Returns set of all actions */
    const vector<AType>& get_actions() const {return actions;};

    /** True if the state is considered terminal (no actions). */
    bool is_terminal() const {return actions.empty();};

    /** Normalizes transition probabilities to sum to one. */
    void normalize(){
        for(AType& a : actions)
            a.normalize();
    }

    /** Checks whether the prescribed action and outcome are correct */
    bool is_action_correct(long aid, numvec nataction) const{
        if( (aid < 0) || ((size_t)aid >= actions.size()))
            return false;

        return actions[aid].is_nature_correct(nataction);
    }

   /** Checks whether the prescribed action correct */
    bool is_action_correct(long aid) const{
        if( (aid < 0) || ((size_t)aid >= actions.size()))
            return false;
        else
            return true;
    }

    /** Returns the mean reward following the action (and outcome). */
    prec_t mean_reward(long actionid, numvec nataction) const{
        if(is_terminal() || !is_valid(actionid)) return 0;
        else return get_action(actionid).mean_reward(nataction);
    }

    /** Returns the mean reward following the action. */
    prec_t mean_reward(long actionid) const{
        if(is_terminal() || !is_valid(actionid)) return 0;
        else return get_action(actionid).mean_reward();
    }

    /** Returns the mean transition probabilities following the action and outcome.
    This class assumes a deterministic policy of the decision maker and
    a randomized policy of nature.

    \param action Deterministic action of the decision maker
    \param nataction Randomized action of nature */
    Transition mean_transition(long action, numvec nataction) const{
        if(is_terminal()) return Transition();
        else return get_action(action).mean_transition(nataction);
    }

    /** Returns the mean transition probabilities following the action and outcome.

    \param action Deterministic action of decision maker */
    Transition mean_transition(long action) const{
        if(is_terminal()) return Transition();
        else return get_action(action).mean_transition();
    }

    /** Returns json representation of the state
    \param stateid Includes also state id*/
    string to_json(long stateid = -1) const{
        string result{"{"};
        result += "\"stateid\" : ";
        result += std::to_string(stateid);
        result += ",\"actions\" : [";
        for(auto ai : indices(actions)){
            const auto& a = actions[ai];
            result += a.to_json(ai);
            result += ",";
        }
        if(!actions.empty()) result.pop_back(); // remove last comma
        result += ("]}");
        return result;
    }
};

// **********************************************************************
// *********************    SPECIFIC STATE DEFINITIONS    ***************
// **********************************************************************

/// Regular MDP state with no outcomes
typedef SAState<RegularAction> RegularState;
/// State with uncertain outcomes with L1 constraints on the distribution
typedef SAState<WeightedOutcomeAction> WeightedRobustState;
}

/// helper functions
namespace internal{
    using namespace craam;

    /// checks state and policy with a policy of nature
    template<class SType>
    bool is_action_correct(const SType& state, long stateid, const std::pair<indvec,vector<numvec>>& policies){
        return state.is_action_correct(policies.first[stateid], policies.second[stateid]);
    }

    /// checks state that does not require nature
    template<class SType>
    bool is_action_correct(const SType& state, long stateid, const indvec& policy){
        return state.is_action_correct(policy[stateid]);
    }
}
<|endoftext|>


<commit_before><commit_msg>Turn an assert into a warning and make onTrackDataReceived more robust<commit_after><|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPrimitivePainter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkPrimitivePainter.h"

#include "vtkActor.h"
#include "vtkCellData.h"
#include "vtkDataSetAttributes.h"
#include "vtkGarbageCollector.h"
#include "vtkGenericVertexAttributeMapping.h"
#include "vtkInformation.h"
#include "vtkInformationIntegerKey.h"
#include "vtkInformationObjectBaseKey.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkShaderDeviceAdapter.h"
#include "vtkShaderProgram.h"
#include "vtkTimerLog.h"
#include "vtkUnsignedCharArray.h"

vtkCxxRevisionMacro(vtkPrimitivePainter, "1.6");
//---------------------------------------------------------------------------
vtkPrimitivePainter::vtkPrimitivePainter()
{
  this->SupportedPrimitive = 0x0; // must be set by subclasses. No primitive
                                  // supported by default.
  this->DisableScalarColor = 0;
  this->OutputData = vtkPolyData::New();
  this->GenericVertexAttributes = false;
}

//---------------------------------------------------------------------------
vtkPrimitivePainter::~vtkPrimitivePainter()
{
  if( this->OutputData )
    {
    this->OutputData->Delete();
    this->OutputData = 0;
    }
}

//---------------------------------------------------------------------------
void vtkPrimitivePainter::ReportReferences(vtkGarbageCollector *collector)
{
  this->Superclass::ReportReferences(collector);
  vtkGarbageCollectorReport(collector, this->OutputData, "Output Data");
}

//---------------------------------------------------------------------------
vtkDataObject* vtkPrimitivePainter::GetOutput()
{
  return this->OutputData;
}

//---------------------------------------------------------------------------
void vtkPrimitivePainter::ProcessInformation(vtkInformation *info)
{
  this->GenericVertexAttributes = false;
  if (info->Has(DATA_ARRAY_TO_VERTEX_ATTRIBUTE()))
    {
    vtkGenericVertexAttributeMapping *mappings =
      vtkGenericVertexAttributeMapping::SafeDownCast(
      info->Get(DATA_ARRAY_TO_VERTEX_ATTRIBUTE()));
    this->GenericVertexAttributes = mappings &&
      (mappings->GetNumberOfMappings() > 0);
    }

  if (info->Has(DISABLE_SCALAR_COLOR()) &&
    info->Get(DISABLE_SCALAR_COLOR()) == 1)
    {
    this->DisableScalarColor = 1;
    }
  else
    {
    this->DisableScalarColor = 0;
    }
}

//---------------------------------------------------------------------------
void vtkPrimitivePainter::PrepareForRendering(vtkRenderer* renderer,
  vtkActor* actor)
{
  // Here, we don't use the this->StaticData flag to mean that the input
  // can never change, since the input may be the output of
  // some filtering painter that filter on actor/renderer properties
  // and not on the input polydata. Hence the input polydata
  // may get modified even if the input to the PolyDataMapper is
  // immutable.

  // If the input has changed update the output.
  if (this->OutputUpdateTime < this->MTime ||
    this->OutputUpdateTime < this->GetInput()->GetMTime())
    {
    this->OutputData->ShallowCopy(this->GetInputAsPolyData());
    this->OutputUpdateTime.Modified();
    }

  this->Superclass::PrepareForRendering(renderer, actor);
}

//---------------------------------------------------------------------------
void vtkPrimitivePainter::RenderInternal(vtkRenderer* renderer,
    vtkActor* act, unsigned long typeflags)
{
  unsigned long supported_typeflags = this->SupportedPrimitive & typeflags;
  if (!supported_typeflags)
    {
    // no supported primitive requested to be rendered.
    this->Superclass::RenderInternal(renderer, act, typeflags);
    return;
    }

  if (!renderer->GetRenderWindow()->GetPainterDeviceAdapter())
    {
    vtkErrorMacro("Painter Device Adapter is missing!");
    return;
    }

  this->Timer->StartTimer();

  int interpolation;
  float tran;
  vtkProperty *prop;
  vtkUnsignedCharArray *c=NULL;
  vtkDataArray *n;
  vtkDataArray *t;
  int tDim;
  vtkPolyData *input = this->GetInputAsPolyData();
  int cellNormals;
  int cellScalars = 0;
  int fieldScalars = 0;

  // get the property
  prop = act->GetProperty();

  // get the transparency
  tran = prop->GetOpacity();

  // if the primitives are invisible then get out of here
  if (tran <= 0.0)
    {
    return;
    }

  // get the shading interpolation
  interpolation = prop->GetInterpolation();

  if (!this->DisableScalarColor)
    {
    // are they cell or point scalars
    c = vtkUnsignedCharArray::SafeDownCast(input->GetPointData()->GetScalars());
    if (!c)
      {
      c = vtkUnsignedCharArray::SafeDownCast(input->GetCellData()->GetScalars());
      cellScalars = 1;
      }

    if (!c)
      {
      c = vtkUnsignedCharArray::SafeDownCast(input->GetFieldData()->
        GetArray("Color"));
      fieldScalars = 1; // note when fieldScalars == 1, also cellScalars == 1.
      // this ensures that primitive painters that do not distinguish between
      // fieldScalars and cellScalars (eg. Verts/Lines/Polys painters) can ignore
      // fieldScalars flag.
      }
    }

  n = input->GetPointData()->GetNormals();
  if (interpolation == VTK_FLAT)
    {
    // shunt point normals.
    n = 0;
    if (this->OutputData->GetPointData()->GetNormals())
      {
      this->OutputData->GetPointData()->SetNormals(0);
      }
    }

  cellNormals = 0;
  if (n == 0 && input->GetCellData()->GetNormals())
    {
    cellNormals = 1;
    n = input->GetCellData()->GetNormals();
    }

  unsigned long idx = 0;
  if (n && !cellNormals)
    {
    idx |= VTK_PDM_NORMALS;
    }
  if (c)
    {
    idx |= VTK_PDM_COLORS;
    if (!fieldScalars && c->GetName())
      {
      // In the future, I will look at the number of components.
      // All paths will have to handle 3 component colors.
      // When using field colors, the c->GetName() condition is not valid,
      // since field data arrays always have names. In that case we
      // forfeit the speed improvement gained by using RGB colors instead
      // or RGBA.
      idx |= VTK_PDM_OPAQUE_COLORS;
      }
    if (cellScalars)
      {
      idx |= VTK_PDM_CELL_COLORS;
      }
    if (fieldScalars)
      {
      idx |= VTK_PDM_FIELD_COLORS;
      }
    }
  if (cellNormals)
    {
    idx |= VTK_PDM_CELL_NORMALS;
    }

  // Texture and color by texture
  t = input->GetPointData()->GetTCoords();
  if ( t )
    {
    tDim = t->GetNumberOfComponents();
    if (tDim > 2)
      {
      vtkDebugMacro(<< "Currently only 1d and 2d textures are supported.\n");
      t = NULL;
      }
    }

  // Set the flags
  if (t)
    {
    idx |= VTK_PDM_TCOORDS;
    }

  if (!act)
    {
    vtkErrorMacro("No actor");
    }

  vtkShaderDeviceAdapter *shaderDevice = NULL;

  if (prop->GetShading() && prop->GetShaderProgram())
    {
    shaderDevice = prop->GetShaderProgram()->GetShaderDeviceAdapter();
    }

  if (shaderDevice && this->GenericVertexAttributes)
    {
    idx |= VTK_PDM_GENERIC_VERTEX_ATTRIBUTES;
    }

  if (this->RenderPrimitive(idx, n, c, t, renderer))
    {
    // subclass rendered the supported primitive successfully.
    // The delegate need not render it.
    typeflags &= (~this->SupportedPrimitive);
    }

  this->Timer->StopTimer();
  this->TimeToDraw = this->Timer->GetElapsedTime();

  this->Superclass::RenderInternal(renderer, act, typeflags);
}

//---------------------------------------------------------------------------
void vtkPrimitivePainter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "SupportedPrimitive: " << this->SupportedPrimitive << endl;
}
<commit_msg>BUG: Allow 3D texture coordinates.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPrimitivePainter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkPrimitivePainter.h"

#include "vtkActor.h"
#include "vtkCellData.h"
#include "vtkDataSetAttributes.h"
#include "vtkGarbageCollector.h"
#include "vtkGenericVertexAttributeMapping.h"
#include "vtkInformation.h"
#include "vtkInformationIntegerKey.h"
#include "vtkInformationObjectBaseKey.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkShaderDeviceAdapter.h"
#include "vtkShaderProgram.h"
#include "vtkTimerLog.h"
#include "vtkUnsignedCharArray.h"

vtkCxxRevisionMacro(vtkPrimitivePainter, "1.7");
//---------------------------------------------------------------------------
vtkPrimitivePainter::vtkPrimitivePainter()
{
  this->SupportedPrimitive = 0x0; // must be set by subclasses. No primitive
                                  // supported by default.
  this->DisableScalarColor = 0;
  this->OutputData = vtkPolyData::New();
  this->GenericVertexAttributes = false;
}

//---------------------------------------------------------------------------
vtkPrimitivePainter::~vtkPrimitivePainter()
{
  if( this->OutputData )
    {
    this->OutputData->Delete();
    this->OutputData = 0;
    }
}

//---------------------------------------------------------------------------
void vtkPrimitivePainter::ReportReferences(vtkGarbageCollector *collector)
{
  this->Superclass::ReportReferences(collector);
  vtkGarbageCollectorReport(collector, this->OutputData, "Output Data");
}

//---------------------------------------------------------------------------
vtkDataObject* vtkPrimitivePainter::GetOutput()
{
  return this->OutputData;
}

//---------------------------------------------------------------------------
void vtkPrimitivePainter::ProcessInformation(vtkInformation *info)
{
  this->GenericVertexAttributes = false;
  if (info->Has(DATA_ARRAY_TO_VERTEX_ATTRIBUTE()))
    {
    vtkGenericVertexAttributeMapping *mappings =
      vtkGenericVertexAttributeMapping::SafeDownCast(
      info->Get(DATA_ARRAY_TO_VERTEX_ATTRIBUTE()));
    this->GenericVertexAttributes = mappings &&
      (mappings->GetNumberOfMappings() > 0);
    }

  if (info->Has(DISABLE_SCALAR_COLOR()) &&
    info->Get(DISABLE_SCALAR_COLOR()) == 1)
    {
    this->DisableScalarColor = 1;
    }
  else
    {
    this->DisableScalarColor = 0;
    }
}

//---------------------------------------------------------------------------
void vtkPrimitivePainter::PrepareForRendering(vtkRenderer* renderer,
  vtkActor* actor)
{
  // Here, we don't use the this->StaticData flag to mean that the input
  // can never change, since the input may be the output of
  // some filtering painter that filter on actor/renderer properties
  // and not on the input polydata. Hence the input polydata
  // may get modified even if the input to the PolyDataMapper is
  // immutable.

  // If the input has changed update the output.
  if (this->OutputUpdateTime < this->MTime ||
    this->OutputUpdateTime < this->GetInput()->GetMTime())
    {
    this->OutputData->ShallowCopy(this->GetInputAsPolyData());
    this->OutputUpdateTime.Modified();
    }

  this->Superclass::PrepareForRendering(renderer, actor);
}

//---------------------------------------------------------------------------
void vtkPrimitivePainter::RenderInternal(vtkRenderer* renderer,
    vtkActor* act, unsigned long typeflags)
{
  unsigned long supported_typeflags = this->SupportedPrimitive & typeflags;
  if (!supported_typeflags)
    {
    // no supported primitive requested to be rendered.
    this->Superclass::RenderInternal(renderer, act, typeflags);
    return;
    }

  if (!renderer->GetRenderWindow()->GetPainterDeviceAdapter())
    {
    vtkErrorMacro("Painter Device Adapter is missing!");
    return;
    }

  this->Timer->StartTimer();

  int interpolation;
  float tran;
  vtkProperty *prop;
  vtkUnsignedCharArray *c=NULL;
  vtkDataArray *n;
  vtkDataArray *t;
  int tDim;
  vtkPolyData *input = this->GetInputAsPolyData();
  int cellNormals;
  int cellScalars = 0;
  int fieldScalars = 0;

  // get the property
  prop = act->GetProperty();

  // get the transparency
  tran = prop->GetOpacity();

  // if the primitives are invisible then get out of here
  if (tran <= 0.0)
    {
    return;
    }

  // get the shading interpolation
  interpolation = prop->GetInterpolation();

  if (!this->DisableScalarColor)
    {
    // are they cell or point scalars
    c = vtkUnsignedCharArray::SafeDownCast(input->GetPointData()->GetScalars());
    if (!c)
      {
      c = vtkUnsignedCharArray::SafeDownCast(input->GetCellData()->GetScalars());
      cellScalars = 1;
      }

    if (!c)
      {
      c = vtkUnsignedCharArray::SafeDownCast(input->GetFieldData()->
        GetArray("Color"));
      fieldScalars = 1; // note when fieldScalars == 1, also cellScalars == 1.
      // this ensures that primitive painters that do not distinguish between
      // fieldScalars and cellScalars (eg. Verts/Lines/Polys painters) can ignore
      // fieldScalars flag.
      }
    }

  n = input->GetPointData()->GetNormals();
  if (interpolation == VTK_FLAT)
    {
    // shunt point normals.
    n = 0;
    if (this->OutputData->GetPointData()->GetNormals())
      {
      this->OutputData->GetPointData()->SetNormals(0);
      }
    }

  cellNormals = 0;
  if (n == 0 && input->GetCellData()->GetNormals())
    {
    cellNormals = 1;
    n = input->GetCellData()->GetNormals();
    }

  unsigned long idx = 0;
  if (n && !cellNormals)
    {
    idx |= VTK_PDM_NORMALS;
    }
  if (c)
    {
    idx |= VTK_PDM_COLORS;
    if (!fieldScalars && c->GetName())
      {
      // In the future, I will look at the number of components.
      // All paths will have to handle 3 component colors.
      // When using field colors, the c->GetName() condition is not valid,
      // since field data arrays always have names. In that case we
      // forfeit the speed improvement gained by using RGB colors instead
      // or RGBA.
      idx |= VTK_PDM_OPAQUE_COLORS;
      }
    if (cellScalars)
      {
      idx |= VTK_PDM_CELL_COLORS;
      }
    if (fieldScalars)
      {
      idx |= VTK_PDM_FIELD_COLORS;
      }
    }
  if (cellNormals)
    {
    idx |= VTK_PDM_CELL_NORMALS;
    }

  // Texture and color by texture
  t = input->GetPointData()->GetTCoords();
  if ( t )
    {
    tDim = t->GetNumberOfComponents();
    if (tDim > 3)
      {
      vtkDebugMacro(<< "Currently only 1d, 2d and 3d texture coordinates are supported.\n");
      t = NULL;
      }
    }

  // Set the flags
  if (t)
    {
    idx |= VTK_PDM_TCOORDS;
    }

  if (!act)
    {
    vtkErrorMacro("No actor");
    }

  vtkShaderDeviceAdapter *shaderDevice = NULL;

  if (prop->GetShading() && prop->GetShaderProgram())
    {
    shaderDevice = prop->GetShaderProgram()->GetShaderDeviceAdapter();
    }

  if (shaderDevice && this->GenericVertexAttributes)
    {
    idx |= VTK_PDM_GENERIC_VERTEX_ATTRIBUTES;
    }

  if (this->RenderPrimitive(idx, n, c, t, renderer))
    {
    // subclass rendered the supported primitive successfully.
    // The delegate need not render it.
    typeflags &= (~this->SupportedPrimitive);
    }

  this->Timer->StopTimer();
  this->TimeToDraw = this->Timer->GetElapsedTime();

  this->Superclass::RenderInternal(renderer, act, typeflags);
}

//---------------------------------------------------------------------------
void vtkPrimitivePainter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "SupportedPrimitive: " << this->SupportedPrimitive << endl;
}
<|endoftext|>


<commit_before>// Virvo - Virtual Reality Volume Rendering
// Copyright (C) 1999-2003 University of Stuttgart, 2004-2005 Brown University
// Contact: Jurgen P. Schulze, jschulze@ucsd.edu
//
// This file is part of Virvo.
//
// Virvo is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library (see license.txt); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include "vvdebugmsg.h"
#include "vvremoteclient.h"

using std::cerr;
using std::endl;

vvRemoteClient::vvRemoteClient(vvVolDesc *vd, vvRenderState renderState,
                               const char *slaveName, int slavePort,
                               const char *slaveFileName)
   : vvRenderer(vd, renderState),
    _slaveName(slaveName),
    _slavePort(slavePort),
    _slaveFileName(slaveFileName),
    _changes(true),
    _viewportWidth(-1),
    _viewportHeight(-1)
{
  vvDebugMsg::msg(1, "vvRemoteClient::vvRemoteClient()");

  initSocket(vd);
}

vvRemoteClient::~vvRemoteClient()
{
  vvDebugMsg::msg(1, "vvRemoteClient::~vvRemoteClient()");

  clearImages();
}

void vvRemoteClient::renderVolumeGL()
{
  GLint vp[4];
  glGetIntegerv(GL_VIEWPORT, vp);
  if(vp[0] != _viewportWidth || vp[1] != _viewportHeight)
  {
    resize(vp[2], vp[3]);
  }

  if (render() != vvRemoteClient::VV_OK)
  {
    vvDebugMsg::msg(0, "vvRemoteClient::renderVolumeGL(): remote rendering error");
  }
  vvRenderer::renderVolumeGL();
}

vvRemoteClient::ErrorType vvRemoteClient::initSocket(vvVolDesc*& vd)
{
  vvDebugMsg::msg(1, "vvRemoteClient::initSocket()");

  _socket = new vvSocketIO(_slavePort, _slaveName, vvSocket::VV_TCP);
  _socket->set_debuglevel(vvDebugMsg::getDebugLevel());

  if (_socket->init() == vvSocket::VV_OK)
  {
    _socket->no_nagle();
    _socket->putBool(_slaveFileName!=NULL);

    if (_slaveFileName)
    {
      _socket->putFileName(_slaveFileName);
      _socket->getVolumeAttributes(vd);
      vvTransFunc tf;
      tf._widgets.removeAll();
      if ((_socket->getTransferFunction(tf)) == vvSocket::VV_OK)
      {
        vd->tf = tf;
      }
    }
    else
    {
      switch (_socket->putVolume(vd))
      {
        case vvSocket::VV_OK:
          cerr << "Volume transferred successfully" << endl;
          break;
        case vvSocket::VV_ALLOC_ERROR:
          cerr << "Not enough memory" << endl;
          return VV_SOCKET_ERROR;
        default:
          cerr << "Cannot write volume to socket" << endl;
          return VV_SOCKET_ERROR;
      }
    }
  }
  else
  {
    cerr << "No connection to remote rendering server established at: " << _slaveName << endl;
    return VV_SOCKET_ERROR;
  }
  return VV_OK;
}

void vvRemoteClient::resize(const int w, const int h)
{
  vvDebugMsg::msg(1, "vvRemoteClient::resize()");
  _changes = true;
  _viewportWidth = w;
  _viewportHeight = h;

  if (_socket->putCommReason(vvSocketIO::VV_RESIZE) == vvSocket::VV_OK)
  {
    _socket->putWinDims(w, h);
  }
}

void vvRemoteClient:: setCurrentFrame(const int index)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setCurrentFrame()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_CURRENT_FRAME) == vvSocket::VV_OK)
  {
    _socket->putInt32(index);
  }
}

void vvRemoteClient::setMipMode(const int mipMode)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setMipMode()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_MIPMODE) == vvSocket::VV_OK)
  {
    _socket->putInt32(mipMode);
  }
}

void vvRemoteClient::setObjectDirection(const vvVector3* od)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setObjectDirection()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_OBJECT_DIRECTION) == vvSocket::VV_OK)
  {
    _socket->putVector3(*od);
  }
}

void vvRemoteClient::setViewingDirection(const vvVector3* vd)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setViewingDirection()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_VIEWING_DIRECTION) == vvSocket::VV_OK)
  {
    _socket->putVector3(*vd);
  }
}

void vvRemoteClient::setPosition(const vvVector3* p)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setPosition()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_POSITION) == vvSocket::VV_OK)
  {
    _socket->putVector3(*p);
  }
}

void vvRemoteClient::setROIEnable(const bool roiEnabled)
{
  vvDebugMsg::msg(1, "vvRemoteClient::setROIEnable()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_TOGGLE_ROI) == vvSocket::VV_OK)
  {
    _socket->putBool(roiEnabled);
  }
}

void vvRemoteClient::setProbePosition(const vvVector3* pos)
{
  vvDebugMsg::msg(1, "vvRemoteClient::setProbePosition()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_ROI_POSITION) == vvSocket::VV_OK)
  {
    _socket->putVector3(*pos);
  }
}

void vvRemoteClient::setProbeSize(const vvVector3* newSize)
{
  vvDebugMsg::msg(1, "vvRemoteClient::setProbeSize()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_ROI_SIZE) == vvSocket::VV_OK)
  {
    _socket->putVector3(*newSize);
  }
}

void vvRemoteClient::updateTransferFunction()
{
  vvDebugMsg::msg(1, "vvRemoteClient::updateTransferFunction()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_TRANSFER_FUNCTION) == vvSocket::VV_OK)
  {
    _socket->putTransferFunction(vd->tf);
  }
}

void vvRemoteClient::setParameter(const vvRenderer::ParameterType param, const float newValue)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setParameter()");
  _changes = true;
  vvRenderer::setParameter(param, newValue);
  if (_socket->putCommReason(vvSocketIO::VV_PARAMETER_1) == vvSocket::VV_OK)
  {
    _socket->putInt32((int32_t)param);
    _socket->putFloat(newValue);
  }
}

void vvRemoteClient::setParameterV3(const vvRenderer::ParameterType param, const vvVector3 &newValue)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setParameter()");
  _changes = true;
  vvRenderer::setParameterV3(param, newValue);
  if (_socket->putCommReason(vvSocketIO::VV_PARAMETER_3) == vvSocket::VV_OK)
  {
    _socket->putInt32((int32_t)param);
    _socket->putVector3(newValue);
  }
}

void vvRemoteClient::setParameterV4(const vvRenderer::ParameterType param, const vvVector4 &newValue)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setParameter()");
  _changes = true;
  vvRenderer::setParameterV4(param, newValue);
  if (_socket->putCommReason(vvSocketIO::VV_PARAMETER_3) == vvSocket::VV_OK)
  {
    _socket->putInt32((int32_t)param);
    _socket->putVector4(newValue);
  }
}

void vvRemoteClient::adjustQuality(const float quality)
{
  vvDebugMsg::msg(3, "vvRemoteClient::adjustQuality()");
  if (_socket->putCommReason(vvSocketIO::VV_QUALITY) == vvSocket::VV_OK)
  {
    _socket->putFloat(quality);
  }
}

void vvRemoteClient::setInterpolation(const bool interpolation)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setInterpolation()");
    if (_socket->putCommReason(vvSocketIO::VV_INTERPOLATION) == vvSocket::VV_OK)
    {
      _socket->putBool(interpolation);
    }
}

void vvRemoteClient::clearImages()
{
  vvDebugMsg::msg(3, "vvRemoteClient::clearImages()");
  for (std::vector<vvImage*>::const_iterator it = _images.begin();
      it != _images.end();
      ++it)
  {
    delete (*it);
  }
  _images.clear();
}
// vim: sw=2:expandtab:softtabstop=2:ts=2:cino=\:0g0t0
<commit_msg>compare corresponding values<commit_after>// Virvo - Virtual Reality Volume Rendering
// Copyright (C) 1999-2003 University of Stuttgart, 2004-2005 Brown University
// Contact: Jurgen P. Schulze, jschulze@ucsd.edu
//
// This file is part of Virvo.
//
// Virvo is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library (see license.txt); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include "vvdebugmsg.h"
#include "vvremoteclient.h"

using std::cerr;
using std::endl;

vvRemoteClient::vvRemoteClient(vvVolDesc *vd, vvRenderState renderState,
                               const char *slaveName, int slavePort,
                               const char *slaveFileName)
   : vvRenderer(vd, renderState),
    _slaveName(slaveName),
    _slavePort(slavePort),
    _slaveFileName(slaveFileName),
    _changes(true),
    _viewportWidth(-1),
    _viewportHeight(-1)
{
  vvDebugMsg::msg(1, "vvRemoteClient::vvRemoteClient()");

  initSocket(vd);
}

vvRemoteClient::~vvRemoteClient()
{
  vvDebugMsg::msg(1, "vvRemoteClient::~vvRemoteClient()");

  clearImages();
}

void vvRemoteClient::renderVolumeGL()
{
  GLint vp[4];
  glGetIntegerv(GL_VIEWPORT, vp);
  if(vp[2] != _viewportWidth || vp[3] != _viewportHeight)
  {
    resize(vp[2], vp[3]);
  }

  if (render() != vvRemoteClient::VV_OK)
  {
    vvDebugMsg::msg(0, "vvRemoteClient::renderVolumeGL(): remote rendering error");
  }
  vvRenderer::renderVolumeGL();
}

vvRemoteClient::ErrorType vvRemoteClient::initSocket(vvVolDesc*& vd)
{
  vvDebugMsg::msg(1, "vvRemoteClient::initSocket()");

  _socket = new vvSocketIO(_slavePort, _slaveName, vvSocket::VV_TCP);
  _socket->set_debuglevel(vvDebugMsg::getDebugLevel());

  if (_socket->init() == vvSocket::VV_OK)
  {
    _socket->no_nagle();
    _socket->putBool(_slaveFileName!=NULL);

    if (_slaveFileName)
    {
      _socket->putFileName(_slaveFileName);
      _socket->getVolumeAttributes(vd);
      vvTransFunc tf;
      tf._widgets.removeAll();
      if ((_socket->getTransferFunction(tf)) == vvSocket::VV_OK)
      {
        vd->tf = tf;
      }
    }
    else
    {
      switch (_socket->putVolume(vd))
      {
        case vvSocket::VV_OK:
          cerr << "Volume transferred successfully" << endl;
          break;
        case vvSocket::VV_ALLOC_ERROR:
          cerr << "Not enough memory" << endl;
          return VV_SOCKET_ERROR;
        default:
          cerr << "Cannot write volume to socket" << endl;
          return VV_SOCKET_ERROR;
      }
    }
  }
  else
  {
    cerr << "No connection to remote rendering server established at: " << _slaveName << endl;
    return VV_SOCKET_ERROR;
  }
  return VV_OK;
}

void vvRemoteClient::resize(const int w, const int h)
{
  vvDebugMsg::msg(1, "vvRemoteClient::resize()");
  _changes = true;
  _viewportWidth = w;
  _viewportHeight = h;

  if (_socket->putCommReason(vvSocketIO::VV_RESIZE) == vvSocket::VV_OK)
  {
    _socket->putWinDims(w, h);
  }
}

void vvRemoteClient:: setCurrentFrame(const int index)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setCurrentFrame()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_CURRENT_FRAME) == vvSocket::VV_OK)
  {
    _socket->putInt32(index);
  }
}

void vvRemoteClient::setMipMode(const int mipMode)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setMipMode()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_MIPMODE) == vvSocket::VV_OK)
  {
    _socket->putInt32(mipMode);
  }
}

void vvRemoteClient::setObjectDirection(const vvVector3* od)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setObjectDirection()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_OBJECT_DIRECTION) == vvSocket::VV_OK)
  {
    _socket->putVector3(*od);
  }
}

void vvRemoteClient::setViewingDirection(const vvVector3* vd)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setViewingDirection()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_VIEWING_DIRECTION) == vvSocket::VV_OK)
  {
    _socket->putVector3(*vd);
  }
}

void vvRemoteClient::setPosition(const vvVector3* p)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setPosition()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_POSITION) == vvSocket::VV_OK)
  {
    _socket->putVector3(*p);
  }
}

void vvRemoteClient::setROIEnable(const bool roiEnabled)
{
  vvDebugMsg::msg(1, "vvRemoteClient::setROIEnable()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_TOGGLE_ROI) == vvSocket::VV_OK)
  {
    _socket->putBool(roiEnabled);
  }
}

void vvRemoteClient::setProbePosition(const vvVector3* pos)
{
  vvDebugMsg::msg(1, "vvRemoteClient::setProbePosition()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_ROI_POSITION) == vvSocket::VV_OK)
  {
    _socket->putVector3(*pos);
  }
}

void vvRemoteClient::setProbeSize(const vvVector3* newSize)
{
  vvDebugMsg::msg(1, "vvRemoteClient::setProbeSize()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_ROI_SIZE) == vvSocket::VV_OK)
  {
    _socket->putVector3(*newSize);
  }
}

void vvRemoteClient::updateTransferFunction()
{
  vvDebugMsg::msg(1, "vvRemoteClient::updateTransferFunction()");
  _changes = true;

  if (_socket->putCommReason(vvSocketIO::VV_TRANSFER_FUNCTION) == vvSocket::VV_OK)
  {
    _socket->putTransferFunction(vd->tf);
  }
}

void vvRemoteClient::setParameter(const vvRenderer::ParameterType param, const float newValue)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setParameter()");
  _changes = true;
  vvRenderer::setParameter(param, newValue);
  if (_socket->putCommReason(vvSocketIO::VV_PARAMETER_1) == vvSocket::VV_OK)
  {
    _socket->putInt32((int32_t)param);
    _socket->putFloat(newValue);
  }
}

void vvRemoteClient::setParameterV3(const vvRenderer::ParameterType param, const vvVector3 &newValue)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setParameter()");
  _changes = true;
  vvRenderer::setParameterV3(param, newValue);
  if (_socket->putCommReason(vvSocketIO::VV_PARAMETER_3) == vvSocket::VV_OK)
  {
    _socket->putInt32((int32_t)param);
    _socket->putVector3(newValue);
  }
}

void vvRemoteClient::setParameterV4(const vvRenderer::ParameterType param, const vvVector4 &newValue)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setParameter()");
  _changes = true;
  vvRenderer::setParameterV4(param, newValue);
  if (_socket->putCommReason(vvSocketIO::VV_PARAMETER_3) == vvSocket::VV_OK)
  {
    _socket->putInt32((int32_t)param);
    _socket->putVector4(newValue);
  }
}

void vvRemoteClient::adjustQuality(const float quality)
{
  vvDebugMsg::msg(3, "vvRemoteClient::adjustQuality()");
  if (_socket->putCommReason(vvSocketIO::VV_QUALITY) == vvSocket::VV_OK)
  {
    _socket->putFloat(quality);
  }
}

void vvRemoteClient::setInterpolation(const bool interpolation)
{
  vvDebugMsg::msg(3, "vvRemoteClient::setInterpolation()");
    if (_socket->putCommReason(vvSocketIO::VV_INTERPOLATION) == vvSocket::VV_OK)
    {
      _socket->putBool(interpolation);
    }
}

void vvRemoteClient::clearImages()
{
  vvDebugMsg::msg(3, "vvRemoteClient::clearImages()");
  for (std::vector<vvImage*>::const_iterator it = _images.begin();
      it != _images.end();
      ++it)
  {
    delete (*it);
  }
  _images.clear();
}
// vim: sw=2:expandtab:softtabstop=2:ts=2:cino=\:0g0t0
<|endoftext|>


<commit_before><commit_msg>Fix clang-tidy warnings (#158)<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2007 Apple 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:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  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.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "SecurityOrigin.h"

#include "CString.h"
#include "KURL.h"
#include "PlatformString.h"
#include "StringHash.h"
#include <wtf/HashSet.h>
#include <wtf/StdLibExtras.h>

namespace WebCore {

typedef HashSet<String, CaseFoldingHash> URLSchemesMap;

static URLSchemesMap& localSchemes()
{
    DEFINE_STATIC_LOCAL(URLSchemesMap, localSchemes, ());

    if (localSchemes.isEmpty()) {
        localSchemes.add("file");
#if PLATFORM(MAC)
        localSchemes.add("applewebdata");
#endif
#if PLATFORM(QT)
        localSchemes.add("qrc");
#endif
    }

    return localSchemes;
}

static URLSchemesMap& noAccessSchemes()
{
    DEFINE_STATIC_LOCAL(URLSchemesMap, noAccessSchemes, ());

    if (noAccessSchemes.isEmpty())
        noAccessSchemes.add("data");

    return noAccessSchemes;
}

static bool isDefaultPortForProtocol(unsigned short port, const String& protocol)
{
    if (protocol.isEmpty())
        return false;

    typedef HashMap<String, unsigned> DefaultPortsMap;
    DEFINE_STATIC_LOCAL(DefaultPortsMap, defaultPorts, ());
    if (defaultPorts.isEmpty()) {
        defaultPorts.set("http", 80);
        defaultPorts.set("https", 443);
        defaultPorts.set("ftp", 21);
        defaultPorts.set("ftps", 990);
    }
    return defaultPorts.get(protocol) == port;
}

SecurityOrigin::SecurityOrigin(const KURL& url)
    : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower())
    , m_host(url.host().isNull() ? "" : url.host().lower())
    , m_port(url.port())
    , m_noAccess(false)
    , m_universalAccess(false)
    , m_domainWasSetInDOM(false)
{
    // These protocols do not create security origins; the owner frame provides the origin
    if (m_protocol == "about" || m_protocol == "javascript")
        m_protocol = "";

    // Some URLs are not allowed access to anything other than themselves.
    if (shouldTreatURLSchemeAsNoAccess(m_protocol))
        m_noAccess = true;

    // document.domain starts as m_host, but can be set by the DOM.
    m_domain = m_host;

    // By default, only local SecurityOrigins can load local resources.
    m_canLoadLocalResources = isLocal();

    if (isDefaultPortForProtocol(m_port, m_protocol))
        m_port = 0;
}

SecurityOrigin::SecurityOrigin(const SecurityOrigin* other)
    : m_protocol(other->m_protocol.copy())
    , m_host(other->m_host.copy())
    , m_domain(other->m_domain.copy())
    , m_port(other->m_port)
    , m_noAccess(other->m_noAccess)
    , m_universalAccess(other->m_universalAccess)
    , m_domainWasSetInDOM(other->m_domainWasSetInDOM)
    , m_canLoadLocalResources(other->m_canLoadLocalResources)
{
}

bool SecurityOrigin::isEmpty() const
{
    return m_protocol.isEmpty();
}

PassRefPtr<SecurityOrigin> SecurityOrigin::create(const KURL& url)
{
    if (!url.isValid())
        return adoptRef(new SecurityOrigin(KURL()));
    return adoptRef(new SecurityOrigin(url));
}

PassRefPtr<SecurityOrigin> SecurityOrigin::createEmpty()
{
    return create(KURL());
}

PassRefPtr<SecurityOrigin> SecurityOrigin::copy()
{
    return adoptRef(new SecurityOrigin(this));
}

void SecurityOrigin::setDomainFromDOM(const String& newDomain)
{
    m_domainWasSetInDOM = true;
    m_domain = newDomain.lower();
}

bool SecurityOrigin::canAccess(const SecurityOrigin* other) const
{
    if (m_universalAccess)
        return true;

    if (m_noAccess || other->m_noAccess)
        return false;

    // Here are two cases where we should permit access:
    //
    // 1) Neither document has set document.domain.  In this case, we insist
    //    that the scheme, host, and port of the URLs match.
    //
    // 2) Both documents have set document.domain.  In this case, we insist
    //    that the documents have set document.domain to the same value and
    //    that the scheme of the URLs match.
    //
    // This matches the behavior of Firefox 2 and Internet Explorer 6.
    //
    // Internet Explorer 7 and Opera 9 are more strict in that they require
    // the port numbers to match when both pages have document.domain set.
    //
    // FIXME: Evaluate whether we can tighten this policy to require matched
    //        port numbers.
    //
    // Opera 9 allows access when only one page has set document.domain, but
    // this is a security vulnerability.

    if (m_protocol == other->m_protocol) {
        if (!m_domainWasSetInDOM && !other->m_domainWasSetInDOM) {
            if (m_host == other->m_host && m_port == other->m_port)
                return true;
        } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) {
            if (m_domain == other->m_domain)
                return true;
        }
    }

    return false;
}

bool SecurityOrigin::canRequest(const KURL& url) const
{
    if (m_universalAccess)
        return true;

    if (m_noAccess)
        return false;

    RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url);

    // We call isSameSchemeHostPort here instead of canAccess because we want
    // to ignore document.domain effects.
    return isSameSchemeHostPort(targetOrigin.get());
}

void SecurityOrigin::grantLoadLocalResources()
{
    // This method exists only to support backwards compatibility with older
    // versions of WebKit.  Granting privileges to some, but not all, documents
    // in a SecurityOrigin is a security hazard because the documents without
    // the privilege can obtain the privilege by injecting script into the
    // documents that have been granted the privilege.
    ASSERT(FrameLoader::allowSubstituteDataAccessToLocal());
    m_canLoadLocalResources = true;
}

void SecurityOrigin::grantUniversalAccess()
{
    m_universalAccess = true;
}

bool SecurityOrigin::isLocal() const
{
    return shouldTreatURLSchemeAsLocal(m_protocol);
}

bool SecurityOrigin::isSecureTransitionTo(const KURL& url) const
{
    // New window created by the application
    if (isEmpty())
        return true;

    RefPtr<SecurityOrigin> other = SecurityOrigin::create(url);
    return canAccess(other.get());
}

String SecurityOrigin::toString() const
{
    if (isEmpty())
        return "null";

    if (m_noAccess)
        return "null";

    if (m_protocol == "file")
        return String("file://");

    Vector<UChar> result;
    result.reserveInitialCapacity(m_protocol.length() + m_host.length() + 10);
    append(result, m_protocol);
    append(result, "://");
    append(result, m_host);

    if (m_port) {
        append(result, ":");
        append(result, String::number(m_port));
    }

    return String::adopt(result);
}

PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& originString)
{
    return SecurityOrigin::create(KURL(KURL(), originString));
}

static const char SeparatorCharacter = '_';

PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const String& databaseIdentifier)
{
    // Make sure there's a first separator
    int separator1 = databaseIdentifier.find(SeparatorCharacter);
    if (separator1 == -1)
        return create(KURL());

    // Make sure there's a second separator
    int separator2 = databaseIdentifier.reverseFind(SeparatorCharacter);
    if (separator2 == -1)
        return create(KURL());

    // Ensure there were at least 2 seperator characters. Some hostnames on intranets have
    // underscores in them, so we'll assume that any additional underscores are part of the host.
    if (separator1 != separator2)
        return create(KURL());

    // Make sure the port section is a valid port number or doesn't exist
    bool portOkay;
    int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay);
    if (!portOkay && separator2 + 1 == static_cast<int>(databaseIdentifier.length()))
        return create(KURL());

    if (port < 0 || port > 65535)
        return create(KURL());

    // Split out the 3 sections of data
    String protocol = databaseIdentifier.substring(0, separator1);
    String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1);
    return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port)));
}

String SecurityOrigin::databaseIdentifier() const
{
    DEFINE_STATIC_LOCAL(String, separatorString, (&SeparatorCharacter, 1));
    return m_protocol + separatorString + m_host + separatorString + String::number(m_port);
}

bool SecurityOrigin::equal(const SecurityOrigin* other) const
{
    if (other == this)
        return true;

    if (!isSameSchemeHostPort(other))
        return false;

    if (m_domainWasSetInDOM != other->m_domainWasSetInDOM)
        return false;

    if (m_domainWasSetInDOM && m_domain != other->m_domain)
        return false;

    return true;
}

bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const
{
    if (m_host != other->m_host)
        return false;

    if (m_protocol != other->m_protocol)
        return false;

    if (m_port != other->m_port)
        return false;

    return true;
}

// static
void SecurityOrigin::registerURLSchemeAsLocal(const String& scheme)
{
    localSchemes().add(scheme);
}

// static
bool SecurityOrigin::shouldTreatURLAsLocal(const String& url)
{
    // This avoids an allocation of another String and the HashSet contains()
    // call for the file: and http: schemes.
    if (url.length() >= 5) {
        const UChar* s = url.characters();
        if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p' && s[4] == ':')
            return false;
        if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e' && s[4] == ':')
            return true;
    }

    int loc = url.find(':');
    if (loc == -1)
        return false;

    String scheme = url.left(loc);
    return localSchemes().contains(scheme);
}

// static
bool SecurityOrigin::shouldTreatURLSchemeAsLocal(const String& scheme)
{
    // This avoids an allocation of another String and the HashSet contains()
    // call for the file: and http: schemes.
    if (scheme.length() == 4) {
        const UChar* s = scheme.characters();
        if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p')
            return false;
        if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e')
            return true;
    }

    if (scheme.isEmpty())
        return false;

    return localSchemes().contains(scheme);
}

// static
void SecurityOrigin::registerURLSchemeAsNoAccess(const String& scheme)
{
    noAccessSchemes().add(scheme);
}

// static
bool SecurityOrigin::shouldTreatURLSchemeAsNoAccess(const String& scheme)
{
    return noAccessSchemes().contains(scheme);
}

} // namespace WebCore
<commit_msg>Build fix: Another missing header.  Arg.<commit_after>/*
 * Copyright (C) 2007 Apple 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:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  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.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "SecurityOrigin.h"

#include "CString.h"
#include "FrameLoader.h"
#include "KURL.h"
#include "PlatformString.h"
#include "StringHash.h"
#include <wtf/HashSet.h>
#include <wtf/StdLibExtras.h>

namespace WebCore {

typedef HashSet<String, CaseFoldingHash> URLSchemesMap;

static URLSchemesMap& localSchemes()
{
    DEFINE_STATIC_LOCAL(URLSchemesMap, localSchemes, ());

    if (localSchemes.isEmpty()) {
        localSchemes.add("file");
#if PLATFORM(MAC)
        localSchemes.add("applewebdata");
#endif
#if PLATFORM(QT)
        localSchemes.add("qrc");
#endif
    }

    return localSchemes;
}

static URLSchemesMap& noAccessSchemes()
{
    DEFINE_STATIC_LOCAL(URLSchemesMap, noAccessSchemes, ());

    if (noAccessSchemes.isEmpty())
        noAccessSchemes.add("data");

    return noAccessSchemes;
}

static bool isDefaultPortForProtocol(unsigned short port, const String& protocol)
{
    if (protocol.isEmpty())
        return false;

    typedef HashMap<String, unsigned> DefaultPortsMap;
    DEFINE_STATIC_LOCAL(DefaultPortsMap, defaultPorts, ());
    if (defaultPorts.isEmpty()) {
        defaultPorts.set("http", 80);
        defaultPorts.set("https", 443);
        defaultPorts.set("ftp", 21);
        defaultPorts.set("ftps", 990);
    }
    return defaultPorts.get(protocol) == port;
}

SecurityOrigin::SecurityOrigin(const KURL& url)
    : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower())
    , m_host(url.host().isNull() ? "" : url.host().lower())
    , m_port(url.port())
    , m_noAccess(false)
    , m_universalAccess(false)
    , m_domainWasSetInDOM(false)
{
    // These protocols do not create security origins; the owner frame provides the origin
    if (m_protocol == "about" || m_protocol == "javascript")
        m_protocol = "";

    // Some URLs are not allowed access to anything other than themselves.
    if (shouldTreatURLSchemeAsNoAccess(m_protocol))
        m_noAccess = true;

    // document.domain starts as m_host, but can be set by the DOM.
    m_domain = m_host;

    // By default, only local SecurityOrigins can load local resources.
    m_canLoadLocalResources = isLocal();

    if (isDefaultPortForProtocol(m_port, m_protocol))
        m_port = 0;
}

SecurityOrigin::SecurityOrigin(const SecurityOrigin* other)
    : m_protocol(other->m_protocol.copy())
    , m_host(other->m_host.copy())
    , m_domain(other->m_domain.copy())
    , m_port(other->m_port)
    , m_noAccess(other->m_noAccess)
    , m_universalAccess(other->m_universalAccess)
    , m_domainWasSetInDOM(other->m_domainWasSetInDOM)
    , m_canLoadLocalResources(other->m_canLoadLocalResources)
{
}

bool SecurityOrigin::isEmpty() const
{
    return m_protocol.isEmpty();
}

PassRefPtr<SecurityOrigin> SecurityOrigin::create(const KURL& url)
{
    if (!url.isValid())
        return adoptRef(new SecurityOrigin(KURL()));
    return adoptRef(new SecurityOrigin(url));
}

PassRefPtr<SecurityOrigin> SecurityOrigin::createEmpty()
{
    return create(KURL());
}

PassRefPtr<SecurityOrigin> SecurityOrigin::copy()
{
    return adoptRef(new SecurityOrigin(this));
}

void SecurityOrigin::setDomainFromDOM(const String& newDomain)
{
    m_domainWasSetInDOM = true;
    m_domain = newDomain.lower();
}

bool SecurityOrigin::canAccess(const SecurityOrigin* other) const
{
    if (m_universalAccess)
        return true;

    if (m_noAccess || other->m_noAccess)
        return false;

    // Here are two cases where we should permit access:
    //
    // 1) Neither document has set document.domain.  In this case, we insist
    //    that the scheme, host, and port of the URLs match.
    //
    // 2) Both documents have set document.domain.  In this case, we insist
    //    that the documents have set document.domain to the same value and
    //    that the scheme of the URLs match.
    //
    // This matches the behavior of Firefox 2 and Internet Explorer 6.
    //
    // Internet Explorer 7 and Opera 9 are more strict in that they require
    // the port numbers to match when both pages have document.domain set.
    //
    // FIXME: Evaluate whether we can tighten this policy to require matched
    //        port numbers.
    //
    // Opera 9 allows access when only one page has set document.domain, but
    // this is a security vulnerability.

    if (m_protocol == other->m_protocol) {
        if (!m_domainWasSetInDOM && !other->m_domainWasSetInDOM) {
            if (m_host == other->m_host && m_port == other->m_port)
                return true;
        } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) {
            if (m_domain == other->m_domain)
                return true;
        }
    }

    return false;
}

bool SecurityOrigin::canRequest(const KURL& url) const
{
    if (m_universalAccess)
        return true;

    if (m_noAccess)
        return false;

    RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url);

    // We call isSameSchemeHostPort here instead of canAccess because we want
    // to ignore document.domain effects.
    return isSameSchemeHostPort(targetOrigin.get());
}

void SecurityOrigin::grantLoadLocalResources()
{
    // This method exists only to support backwards compatibility with older
    // versions of WebKit.  Granting privileges to some, but not all, documents
    // in a SecurityOrigin is a security hazard because the documents without
    // the privilege can obtain the privilege by injecting script into the
    // documents that have been granted the privilege.
    ASSERT(FrameLoader::allowSubstituteDataAccessToLocal());
    m_canLoadLocalResources = true;
}

void SecurityOrigin::grantUniversalAccess()
{
    m_universalAccess = true;
}

bool SecurityOrigin::isLocal() const
{
    return shouldTreatURLSchemeAsLocal(m_protocol);
}

bool SecurityOrigin::isSecureTransitionTo(const KURL& url) const
{
    // New window created by the application
    if (isEmpty())
        return true;

    RefPtr<SecurityOrigin> other = SecurityOrigin::create(url);
    return canAccess(other.get());
}

String SecurityOrigin::toString() const
{
    if (isEmpty())
        return "null";

    if (m_noAccess)
        return "null";

    if (m_protocol == "file")
        return String("file://");

    Vector<UChar> result;
    result.reserveInitialCapacity(m_protocol.length() + m_host.length() + 10);
    append(result, m_protocol);
    append(result, "://");
    append(result, m_host);

    if (m_port) {
        append(result, ":");
        append(result, String::number(m_port));
    }

    return String::adopt(result);
}

PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& originString)
{
    return SecurityOrigin::create(KURL(KURL(), originString));
}

static const char SeparatorCharacter = '_';

PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const String& databaseIdentifier)
{
    // Make sure there's a first separator
    int separator1 = databaseIdentifier.find(SeparatorCharacter);
    if (separator1 == -1)
        return create(KURL());

    // Make sure there's a second separator
    int separator2 = databaseIdentifier.reverseFind(SeparatorCharacter);
    if (separator2 == -1)
        return create(KURL());

    // Ensure there were at least 2 seperator characters. Some hostnames on intranets have
    // underscores in them, so we'll assume that any additional underscores are part of the host.
    if (separator1 != separator2)
        return create(KURL());

    // Make sure the port section is a valid port number or doesn't exist
    bool portOkay;
    int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay);
    if (!portOkay && separator2 + 1 == static_cast<int>(databaseIdentifier.length()))
        return create(KURL());

    if (port < 0 || port > 65535)
        return create(KURL());

    // Split out the 3 sections of data
    String protocol = databaseIdentifier.substring(0, separator1);
    String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1);
    return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port)));
}

String SecurityOrigin::databaseIdentifier() const
{
    DEFINE_STATIC_LOCAL(String, separatorString, (&SeparatorCharacter, 1));
    return m_protocol + separatorString + m_host + separatorString + String::number(m_port);
}

bool SecurityOrigin::equal(const SecurityOrigin* other) const
{
    if (other == this)
        return true;

    if (!isSameSchemeHostPort(other))
        return false;

    if (m_domainWasSetInDOM != other->m_domainWasSetInDOM)
        return false;

    if (m_domainWasSetInDOM && m_domain != other->m_domain)
        return false;

    return true;
}

bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const
{
    if (m_host != other->m_host)
        return false;

    if (m_protocol != other->m_protocol)
        return false;

    if (m_port != other->m_port)
        return false;

    return true;
}

// static
void SecurityOrigin::registerURLSchemeAsLocal(const String& scheme)
{
    localSchemes().add(scheme);
}

// static
bool SecurityOrigin::shouldTreatURLAsLocal(const String& url)
{
    // This avoids an allocation of another String and the HashSet contains()
    // call for the file: and http: schemes.
    if (url.length() >= 5) {
        const UChar* s = url.characters();
        if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p' && s[4] == ':')
            return false;
        if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e' && s[4] == ':')
            return true;
    }

    int loc = url.find(':');
    if (loc == -1)
        return false;

    String scheme = url.left(loc);
    return localSchemes().contains(scheme);
}

// static
bool SecurityOrigin::shouldTreatURLSchemeAsLocal(const String& scheme)
{
    // This avoids an allocation of another String and the HashSet contains()
    // call for the file: and http: schemes.
    if (scheme.length() == 4) {
        const UChar* s = scheme.characters();
        if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p')
            return false;
        if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e')
            return true;
    }

    if (scheme.isEmpty())
        return false;

    return localSchemes().contains(scheme);
}

// static
void SecurityOrigin::registerURLSchemeAsNoAccess(const String& scheme)
{
    noAccessSchemes().add(scheme);
}

// static
bool SecurityOrigin::shouldTreatURLSchemeAsNoAccess(const String& scheme)
{
    return noAccessSchemes().contains(scheme);
}

} // namespace WebCore
<|endoftext|>