<commit_before>#include "gorgone.h"
using namespace cv;
using namespace ofxCv;
int accum = 0;

void gorgone::setup()
{
  ofSetLogLevel(OF_LOG_NOTICE);
  masterIp = "Mac-Pro-de-10-52.local";
  appName = "gorgone-1";
  parseCmdLineOptions();
  vidGrabber.setup(filename);
  svgInterp.setup();
  jamoma.setup((void*) this, appName, masterIp);
  motionDetector.setup(&jamoma);
  irisDetector.setJamomaRef(&jamoma);
  counter = 0;
}

void gorgone::exit(){
  setPwm(0);
#ifdef TARGET_RASPBERRY_PI
  vidGrabber.led.switchOffIR();
#endif
}

void gorgone::update()
{
  ofLogVerbose("gorgone") << ofGetFrameRate() << " fps" << endl;

  vidGrabber.update();

  if ( vidGrabber.isFrameNew() ){
    frame = vidGrabber.getFrame();

    if ( bMotion ){
      motionDetector.update(frame);
    }

    if( bTracking ){

      if ( frame.cols == 0 ) return;

      cv::Mat gray;
      if ( frame.channels() == 1 ){
        gray = frame.clone();
      } else {
        cv::cvtColor(frame, gray, CV_RGB2GRAY);
      }

      ofLogVerbose("gorgone") << "new frame to process : " << gray.cols << "x" << gray.rows << endl;

      irisDetector.updateBool(gray);
    }
  }

  if (bComputeCode) {
    irisDetector.computeCode();
    bComputeCode=false;
    jamoma.mComputeIrisCodeParameter.set("value", bComputeCode);

/*
// desactivated because Max doesn't handle list longer than 256 item, yes this still happens in 2015...
    TTValue v;
    Mat code = irisDetector.getIrisCode();
    v.push_back(code.cols);
    v.push_back(code.rows);
    uchar* p;
    for (int i = 0; i < code.rows; i++ ){
      p=code.ptr<uchar>(i);
      for (int j = 0; j < code.cols; j++ ){
        v.push_back((int) p[j]);
      }
    }
    cout << "v size : " << v.size() << endl;
    jamoma.mTrackingIrisCodeReturn.set("value",v);
*/
  }

  Mat img = irisDetector.getIrisCode();
  if( bDisplaying && irisDetector.newCode && img.total() > 0 ) {

    if ( irisDetector.newCode ){
      svgInterp.coeff.clear();
      ofLogVerbose("gorgone") << "code image resolution : " << img.cols << "x" << img.rows << endl;
      uchar* p;
      for (int i = 0; i < img.rows; i++ ){
        float avg=0;
        p=img.ptr<uchar>(i);
        for (int j = 0; j < img.cols; j++ ){
          avg+=p[j] / 255.;
        }
        avg/=img.cols;
        svgInterp.coeff.push_back(avg);
      }
      irisDetector.newCode = false;

      TTValue v;
      for (int i = 0; i<svgInterp.coeff.size(); i++){
        v.push_back(svgInterp.coeff[i]);
      }
      jamoma.mTrackingIrisCodeReturn.set("value", v);
    }
  }
}

void gorgone::draw()
{
  //vidGrabber.draw(0,0);
  drawMat(frame,0,0);
  if ( svgInterp.updateBool() ){
    TTValue x,y;
    ofPolyline line = svgInterp.interpolatedLine;
    ofLogNotice("gorgone") << "update drawing with " << line.size() << "points" << endl;
    for (int i=0; i<line.size(); i++){
      x.push_back(line[i].x);
      y.push_back(line[i].y);
    }

    jamoma.mDrawingShapeXReturn.set("value", x);
    jamoma.mDrawingShapeYReturn.set("value", y);
  }
  if ( bTracking )
    irisDetector.drawEyes();
  if ( bDisplaying )
    svgInterp.draw();
}

void gorgone::keyPressed(int key)
{
  ofLogVerbose("gorgone") << "keypressed : " << key << endl;
  switch (key){
    case 's':
      irisDetector.save();
      break;
    case ' ':
      irisDetector.reset();
      break;
    case 'c':
      bComputeCode=true;
      break;
    case 'm':
      bMotion = !bMotion;
      break;
    case 't':
      bTracking = !bTracking;
      if ( bTracking ) irisDetector.reset();
#ifdef TARGET_RASPBERRY_PI
      if ( bTracking ) vidGrabber.led.switchOnIR();
      else vidGrabber.led.switchOffIR();
#endif
      break;
    case 'd':
      bDisplaying = !bDisplaying;
      break;
#ifdef TARGET_RASPBERRY_PI
    case 'i':
      vidGrabber.led.switchOnIR();
      break;
    case 'o':
      vidGrabber.led.switchOffIR();
      break;
    case 'w':
      vidGrabber.led.switchOnWhite();
      break;
    case 'x':
      vidGrabber.led.switchOffWhite();
      break;
#endif
    case 357 : // arrow up
      svgInterp.selectedId = counter++;
      break;
    case 359: // arrow down
      svgInterp.selectedId = counter--;
      break;
    default :
      break;
  }
}

void gorgone::messageReceived(ofMessage& message)
{
}

void gorgone::parseCmdLineOptions(){
  vector<string> keys = ofxArgParser::allKeys();
  for (int i = 0; i < keys.size(); i++) {
    if ( keys[i] == "f" )   filename   = ofxArgParser::getValue(keys[i]);
    else if ( keys[i] == "name" ) appName =  ofxArgParser::getValue(keys[i]);
    else if ( keys[i] == "masterIp" ) masterIp =  ofxArgParser::getValue(keys[i]);
    else if ( keys[i] == "verbose" ) { // vebose level, value : 0..5, default 1 (OF_LOG_NOTICE)
      int logLevel;
      istringstream( ofxArgParser::getValue(keys[i]) ) >> logLevel;
      ofSetLogLevel((ofLogLevel) logLevel);
    }

    ofLogNotice("gorgone") << "key: " << keys[i] << ", value: " << ofxArgParser::getValue(keys[i]) << endl;
  }
}

void gorgone::setPwm(float pc){
#ifdef TARGET_RASPBERRY_PI
  ofstream file;
  file.open("/dev/servoblaster", ios::in);
  file << "0=" << pc << "%" << endl;
  file.close();
#endif
}
<commit_msg>print enabled step on screen<commit_after>#include "gorgone.h"
using namespace cv;
using namespace ofxCv;
int accum = 0;

void gorgone::setup()
{
  ofSetLogLevel(OF_LOG_NOTICE);
  masterIp = "Mac-Pro-de-10-52.local";
  appName = "gorgone-1";
  parseCmdLineOptions();
  vidGrabber.setup(filename);
  svgInterp.setup();
  jamoma.setup((void*) this, appName, masterIp);
  motionDetector.setup(&jamoma);
  irisDetector.setJamomaRef(&jamoma);
  counter = 0;
}

void gorgone::exit(){
  setPwm(0);
#ifdef TARGET_RASPBERRY_PI
  vidGrabber.led.switchOffIR();
#endif
}

void gorgone::update()
{
  ofLogVerbose("gorgone") << ofGetFrameRate() << " fps" << endl;

  vidGrabber.update();

  if ( vidGrabber.isFrameNew() ){
    frame = vidGrabber.getFrame();

    if ( bMotion ){
      motionDetector.update(frame);
    }

    if( bTracking ){

      if ( frame.cols == 0 ) return;

      cv::Mat gray;
      if ( frame.channels() == 1 ){
        gray = frame.clone();
      } else {
        cv::cvtColor(frame, gray, CV_RGB2GRAY);
      }

      ofLogVerbose("gorgone") << "new frame to process : " << gray.cols << "x" << gray.rows << endl;

      irisDetector.updateBool(gray);
    }
  }

  if (bComputeCode) {
    irisDetector.computeCode();
    bComputeCode=false;
    jamoma.mComputeIrisCodeParameter.set("value", bComputeCode);

/*
// desactivated because Max doesn't handle list longer than 256 item, yes this still happens in 2015...
    TTValue v;
    Mat code = irisDetector.getIrisCode();
    v.push_back(code.cols);
    v.push_back(code.rows);
    uchar* p;
    for (int i = 0; i < code.rows; i++ ){
      p=code.ptr<uchar>(i);
      for (int j = 0; j < code.cols; j++ ){
        v.push_back((int) p[j]);
      }
    }
    cout << "v size : " << v.size() << endl;
    jamoma.mTrackingIrisCodeReturn.set("value",v);
*/
  }

  Mat img = irisDetector.getIrisCode();
  if( bDisplaying && irisDetector.newCode && img.total() > 0 ) {

    if ( irisDetector.newCode ){
      svgInterp.coeff.clear();
      ofLogVerbose("gorgone") << "code image resolution : " << img.cols << "x" << img.rows << endl;
      uchar* p;
      for (int i = 0; i < img.rows; i++ ){
        float avg=0;
        p=img.ptr<uchar>(i);
        for (int j = 0; j < img.cols; j++ ){
          avg+=p[j] / 255.;
        }
        avg/=img.cols;
        svgInterp.coeff.push_back(avg);
      }
      irisDetector.newCode = false;

      TTValue v;
      for (int i = 0; i<svgInterp.coeff.size(); i++){
        v.push_back(svgInterp.coeff[i]);
      }
      jamoma.mTrackingIrisCodeReturn.set("value", v);
    }
  }
}

void gorgone::draw()
{
  //vidGrabber.draw(0,0);
  drawMat(frame,0,0);
  if ( svgInterp.updateBool() ){
    TTValue x,y;
    ofPolyline line = svgInterp.interpolatedLine;
    ofLogNotice("gorgone") << "update drawing with " << line.size() << "points" << endl;
    for (int i=0; i<line.size(); i++){
      x.push_back(line[i].x);
      y.push_back(line[i].y);
    }

    jamoma.mDrawingShapeXReturn.set("value", x);
    jamoma.mDrawingShapeYReturn.set("value", y);
  }
  if ( bTracking ) {
    ofDrawBitmapStringHighlight("eye tracking", 10, 400);
    irisDetector.drawEyes();
  }
  if ( bDisplaying ) {
    ofDrawBitmapStringHighlight("laser drawing", 200, 400);
    svgInterp.draw();
  }
  if ( bMotion ){
    ofDrawBitmapStringHighlight("motion detection", 400, 400);
  }
}

void gorgone::keyPressed(int key)
{
  ofLogVerbose("gorgone") << "keypressed : " << key << endl;
  switch (key){
    case 's':
      irisDetector.save();
      break;
    case ' ':
      irisDetector.reset();
      break;
    case 'c':
      bComputeCode=true;
      break;
    case 'm':
      bMotion = !bMotion;
      break;
    case 't':
      bTracking = !bTracking;
      if ( bTracking ) irisDetector.reset();
#ifdef TARGET_RASPBERRY_PI
      if ( bTracking ) vidGrabber.led.switchOnIR();
      else vidGrabber.led.switchOffIR();
#endif
      break;
    case 'd':
      bDisplaying = !bDisplaying;
      break;
#ifdef TARGET_RASPBERRY_PI
    case 'i':
      vidGrabber.led.switchOnIR();
      break;
    case 'o':
      vidGrabber.led.switchOffIR();
      break;
    case 'w':
      vidGrabber.led.switchOnWhite();
      break;
    case 'x':
      vidGrabber.led.switchOffWhite();
      break;
#endif
    case 357 : // arrow up
      svgInterp.selectedId = counter++;
      break;
    case 359: // arrow down
      svgInterp.selectedId = counter--;
      break;
    default :
      break;
  }
}

void gorgone::messageReceived(ofMessage& message)
{
}

void gorgone::parseCmdLineOptions(){
  vector<string> keys = ofxArgParser::allKeys();
  for (int i = 0; i < keys.size(); i++) {
    if ( keys[i] == "f" )   filename   = ofxArgParser::getValue(keys[i]);
    else if ( keys[i] == "name" ) appName =  ofxArgParser::getValue(keys[i]);
    else if ( keys[i] == "masterIp" ) masterIp =  ofxArgParser::getValue(keys[i]);
    else if ( keys[i] == "verbose" ) { // vebose level, value : 0..5, default 1 (OF_LOG_NOTICE)
      int logLevel;
      istringstream( ofxArgParser::getValue(keys[i]) ) >> logLevel;
      ofSetLogLevel((ofLogLevel) logLevel);
    }

    ofLogNotice("gorgone") << "key: " << keys[i] << ", value: " << ofxArgParser::getValue(keys[i]) << endl;
  }
}

void gorgone::setPwm(float pc){
#ifdef TARGET_RASPBERRY_PI
  ofstream file;
  file.open("/dev/servoblaster", ios::in);
  file << "0=" << pc << "%" << endl;
  file.close();
#endif
}
<|endoftext|>


<commit_before>//
// Aspia Project
// Copyright (C) 2018 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// 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 General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "net/network_channel_client.h"
#include "base/cpuid.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "build/version.h"
#include "crypto/cryptor_aes256_gcm.h"
#include "crypto/cryptor_chacha20_poly1305.h"
#include "crypto/secure_memory.h"
#include "net/srp_client_context.h"

#include <QNetworkProxy>

#if defined(OS_WIN)
#include <winsock2.h>
#include <mstcpip.h>
#endif // defined(OS_WIN)

namespace net {

namespace {

QByteArray serializeMessage(const google::protobuf::MessageLite& message)
{
    size_t size = message.ByteSizeLong();
    if (!size)
    {
        LOG(LS_WARNING) << "Empty messages are not allowed";
        return QByteArray();
    }

    QByteArray buffer;
    buffer.resize(size);

    message.SerializeWithCachedSizesToArray(reinterpret_cast<uint8_t*>(buffer.data()));
    return buffer;
}

} // namespace

ChannelClient::ChannelClient(QObject* parent)
    : Channel(ChannelType::CLIENT, new QTcpSocket(), parent)
{
    // We must enable this option before the connection is established.
    socket_->setSocketOption(QTcpSocket::KeepAliveOption, 1);

    connect(socket_, &QTcpSocket::connected, this, &ChannelClient::onConnected);
}

ChannelClient::~ChannelClient()
{
    crypto::memZero(&password_);
}

void ChannelClient::connectToHost(const QString& address, int port,
                                  const QString& username, const QString& password,
                                  proto::SessionType session_type)
{
    username_ = username;
    password_ = password;
    session_type_ = session_type;

    socket_->setProxy(QNetworkProxy::NoProxy);
    socket_->connectToHost(address, port);
}

void ChannelClient::internalMessageReceived(const QByteArray& buffer)
{
    switch (key_exchange_state_)
    {
        case KeyExchangeState::HELLO:
            readServerHello(buffer);
            break;

        case KeyExchangeState::KEY_EXCHANGE:
            readServerKeyExchange(buffer);
            break;

        case KeyExchangeState::SESSION:
            readSessionChallenge(buffer);
            break;

        default:
            break;
    }
}

void ChannelClient::internalMessageWritten()
{
    switch (key_exchange_state_)
    {
        case KeyExchangeState::DONE:
        {
            channel_state_ = ChannelState::ENCRYPTED;
            srp_client_.reset();

            emit connected();
        }
        break;

        default:
            break;
    }
}

void ChannelClient::onConnected()
{
    channel_state_ = ChannelState::CONNECTED;

    // Disable the Nagle algorithm for the socket.
    socket_->setSocketOption(QTcpSocket::LowDelayOption, 1);

#if defined(OS_WIN)
    struct tcp_keepalive alive;

    alive.onoff = 1; // On.
    alive.keepalivetime = 30000; // 30 seconds.
    alive.keepaliveinterval = 5000; // 5 seconds.

    DWORD bytes_returned;

    if (WSAIoctl(socket_->socketDescriptor(), SIO_KEEPALIVE_VALS,
                 &alive, sizeof(alive), nullptr, 0, &bytes_returned,
                 nullptr, nullptr) == SOCKET_ERROR)
    {
        PLOG(LS_WARNING) << "WSAIoctl failed";
    }
#endif

    uint32_t methods = proto::METHOD_SRP_CHACHA20_POLY1305;

    if (base::CPUID::hasAesNi())
        methods |= proto::METHOD_SRP_AES256_GCM;

    proto::ClientHello client_hello;
    client_hello.set_methods(methods);

    // Send ClientHello to server.
    sendInternal(serializeMessage(client_hello));
}

void ChannelClient::readServerHello(const QByteArray& buffer)
{
    key_exchange_state_ = KeyExchangeState::IDENTIFY;

    proto::ServerHello server_hello;
    if (!server_hello.ParseFromArray(buffer.constData(), buffer.size()))
    {
        emit errorOccurred(Error::PROTOCOL_FAILURE);
        return;
    }

    srp_client_.reset(SrpClientContext::create(server_hello.method(), username_, password_));
    if (!srp_client_)
    {
        LOG(LS_WARNING) << "Unable to create SRP client";
        emit errorOccurred(Error::UNKNOWN);
        return;
    }

    std::unique_ptr<proto::SrpIdentify> identify(srp_client_->identify());
    if (!identify)
    {
        LOG(LS_WARNING) << "Error when creating identify";
        emit errorOccurred(Error::UNKNOWN);
        return;
    }

    key_exchange_state_ = KeyExchangeState::KEY_EXCHANGE;
    sendInternal(serializeMessage(*identify));
}

void ChannelClient::readServerKeyExchange(const QByteArray& buffer)
{
    DCHECK(srp_client_);

    proto::SrpServerKeyExchange server_key_exchange;
    if (!server_key_exchange.ParseFromArray(buffer.constData(), buffer.size()))
    {
        emit errorOccurred(Error::PROTOCOL_FAILURE);
        return;
    }

    std::unique_ptr<proto::SrpClientKeyExchange> client_key_exchange(
        srp_client_->readServerKeyExchange(server_key_exchange));
    if (!client_key_exchange)
    {
        LOG(LS_WARNING) << "Error when reading server key exchange";
        emit errorOccurred(Error::UNKNOWN);
        return;
    }

    key_exchange_state_ = KeyExchangeState::SESSION;
    sendInternal(serializeMessage(*client_key_exchange));
}

void ChannelClient::readSessionChallenge(const QByteArray& buffer)
{
    DCHECK(srp_client_);

    switch (srp_client_->method())
    {
        case proto::METHOD_SRP_AES256_GCM:
        {
            cryptor_.reset(crypto::CryptorAes256Gcm::create(
                srp_client_->key(), srp_client_->encryptIv(), srp_client_->decryptIv()));
        }
        break;

        case proto::METHOD_SRP_CHACHA20_POLY1305:
        {
            cryptor_.reset(crypto::CryptorChaCha20Poly1305::create(
                srp_client_->key(), srp_client_->encryptIv(), srp_client_->decryptIv()));
        }
        break;

        default:
            LOG(LS_WARNING) << "Unknown encryption method: " << srp_client_->method();
            break;
    }

    if (!cryptor_)
    {
        LOG(LS_WARNING) << "Unable to create cryptor";
        emit errorOccurred(Error::UNKNOWN);
        return;
    }

    QByteArray session_challenge_buffer;
    session_challenge_buffer.resize(cryptor_->decryptedDataSize(buffer.size()));

    if (!cryptor_->decrypt(buffer.constData(), buffer.size(), session_challenge_buffer.data()))
    {
        emit errorOccurred(Error::AUTHENTICATION_FAILURE);
        return;
    }

    proto::SessionChallenge session_challenge;
    if (!session_challenge.ParseFromArray(session_challenge_buffer.constData(),
                                          session_challenge_buffer.size()))
    {
        emit errorOccurred(Error::AUTHENTICATION_FAILURE);
        return;
    }

    if (!(session_challenge.session_types() & session_type_))
    {
        emit errorOccurred(Error::SESSION_TYPE_NOT_ALLOWED);
        return;
    }

    const proto::Version& host_version = session_challenge.version();

    peer_version_ = base::Version(
        host_version.major(), host_version.minor(), host_version.patch());

    proto::SessionResponse session_response;
    session_response.set_session_type(session_type_);

    proto::Version* client_version = session_response.mutable_version();
    client_version->set_major(ASPIA_VERSION_MAJOR);
    client_version->set_minor(ASPIA_VERSION_MINOR);
    client_version->set_patch(ASPIA_VERSION_PATCH);

    QByteArray session_response_buffer = serializeMessage(session_response);
    if (session_response_buffer.isEmpty())
    {
        LOG(LS_WARNING) << "Error when creating session response";
        emit errorOccurred(Error::UNKNOWN);
        return;
    }

    QByteArray encrypted_buffer;
    encrypted_buffer.resize(cryptor_->encryptedDataSize(session_response_buffer.size()));

    if (!cryptor_->encrypt(session_response_buffer.constData(),
                           session_response_buffer.size(),
                           encrypted_buffer.data()))
    {
        emit errorOccurred(Error::ENCRYPTION_FAILURE);
        return;
    }

    // After the successful completion of the key exchange, we pause the channel.
    // To continue receiving messages, slot |start| must be called.
    pause();

    key_exchange_state_ = KeyExchangeState::DONE;
    sendInternal(encrypted_buffer);
}

} // namespace net
<commit_msg>- Set keep live timeout to 60 seconds.<commit_after>//
// Aspia Project
// Copyright (C) 2018 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// 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 General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "net/network_channel_client.h"
#include "base/cpuid.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "build/version.h"
#include "crypto/cryptor_aes256_gcm.h"
#include "crypto/cryptor_chacha20_poly1305.h"
#include "crypto/secure_memory.h"
#include "net/srp_client_context.h"

#include <QNetworkProxy>

#if defined(OS_WIN)
#include <winsock2.h>
#include <mstcpip.h>
#endif // defined(OS_WIN)

namespace net {

namespace {

QByteArray serializeMessage(const google::protobuf::MessageLite& message)
{
    size_t size = message.ByteSizeLong();
    if (!size)
    {
        LOG(LS_WARNING) << "Empty messages are not allowed";
        return QByteArray();
    }

    QByteArray buffer;
    buffer.resize(size);

    message.SerializeWithCachedSizesToArray(reinterpret_cast<uint8_t*>(buffer.data()));
    return buffer;
}

} // namespace

ChannelClient::ChannelClient(QObject* parent)
    : Channel(ChannelType::CLIENT, new QTcpSocket(), parent)
{
    // We must enable this option before the connection is established.
    socket_->setSocketOption(QTcpSocket::KeepAliveOption, 1);

    connect(socket_, &QTcpSocket::connected, this, &ChannelClient::onConnected);
}

ChannelClient::~ChannelClient()
{
    crypto::memZero(&password_);
}

void ChannelClient::connectToHost(const QString& address, int port,
                                  const QString& username, const QString& password,
                                  proto::SessionType session_type)
{
    username_ = username;
    password_ = password;
    session_type_ = session_type;

    socket_->setProxy(QNetworkProxy::NoProxy);
    socket_->connectToHost(address, port);
}

void ChannelClient::internalMessageReceived(const QByteArray& buffer)
{
    switch (key_exchange_state_)
    {
        case KeyExchangeState::HELLO:
            readServerHello(buffer);
            break;

        case KeyExchangeState::KEY_EXCHANGE:
            readServerKeyExchange(buffer);
            break;

        case KeyExchangeState::SESSION:
            readSessionChallenge(buffer);
            break;

        default:
            break;
    }
}

void ChannelClient::internalMessageWritten()
{
    switch (key_exchange_state_)
    {
        case KeyExchangeState::DONE:
        {
            channel_state_ = ChannelState::ENCRYPTED;
            srp_client_.reset();

            emit connected();
        }
        break;

        default:
            break;
    }
}

void ChannelClient::onConnected()
{
    channel_state_ = ChannelState::CONNECTED;

    // Disable the Nagle algorithm for the socket.
    socket_->setSocketOption(QTcpSocket::LowDelayOption, 1);

#if defined(OS_WIN)
    struct tcp_keepalive alive;

    alive.onoff = 1; // On.
    alive.keepalivetime = 60000; // 60 seconds.
    alive.keepaliveinterval = 5000; // 5 seconds.

    DWORD bytes_returned;

    if (WSAIoctl(socket_->socketDescriptor(), SIO_KEEPALIVE_VALS,
                 &alive, sizeof(alive), nullptr, 0, &bytes_returned,
                 nullptr, nullptr) == SOCKET_ERROR)
    {
        PLOG(LS_WARNING) << "WSAIoctl failed";
    }
#endif

    uint32_t methods = proto::METHOD_SRP_CHACHA20_POLY1305;

    if (base::CPUID::hasAesNi())
        methods |= proto::METHOD_SRP_AES256_GCM;

    proto::ClientHello client_hello;
    client_hello.set_methods(methods);

    // Send ClientHello to server.
    sendInternal(serializeMessage(client_hello));
}

void ChannelClient::readServerHello(const QByteArray& buffer)
{
    key_exchange_state_ = KeyExchangeState::IDENTIFY;

    proto::ServerHello server_hello;
    if (!server_hello.ParseFromArray(buffer.constData(), buffer.size()))
    {
        emit errorOccurred(Error::PROTOCOL_FAILURE);
        return;
    }

    srp_client_.reset(SrpClientContext::create(server_hello.method(), username_, password_));
    if (!srp_client_)
    {
        LOG(LS_WARNING) << "Unable to create SRP client";
        emit errorOccurred(Error::UNKNOWN);
        return;
    }

    std::unique_ptr<proto::SrpIdentify> identify(srp_client_->identify());
    if (!identify)
    {
        LOG(LS_WARNING) << "Error when creating identify";
        emit errorOccurred(Error::UNKNOWN);
        return;
    }

    key_exchange_state_ = KeyExchangeState::KEY_EXCHANGE;
    sendInternal(serializeMessage(*identify));
}

void ChannelClient::readServerKeyExchange(const QByteArray& buffer)
{
    DCHECK(srp_client_);

    proto::SrpServerKeyExchange server_key_exchange;
    if (!server_key_exchange.ParseFromArray(buffer.constData(), buffer.size()))
    {
        emit errorOccurred(Error::PROTOCOL_FAILURE);
        return;
    }

    std::unique_ptr<proto::SrpClientKeyExchange> client_key_exchange(
        srp_client_->readServerKeyExchange(server_key_exchange));
    if (!client_key_exchange)
    {
        LOG(LS_WARNING) << "Error when reading server key exchange";
        emit errorOccurred(Error::UNKNOWN);
        return;
    }

    key_exchange_state_ = KeyExchangeState::SESSION;
    sendInternal(serializeMessage(*client_key_exchange));
}

void ChannelClient::readSessionChallenge(const QByteArray& buffer)
{
    DCHECK(srp_client_);

    switch (srp_client_->method())
    {
        case proto::METHOD_SRP_AES256_GCM:
        {
            cryptor_.reset(crypto::CryptorAes256Gcm::create(
                srp_client_->key(), srp_client_->encryptIv(), srp_client_->decryptIv()));
        }
        break;

        case proto::METHOD_SRP_CHACHA20_POLY1305:
        {
            cryptor_.reset(crypto::CryptorChaCha20Poly1305::create(
                srp_client_->key(), srp_client_->encryptIv(), srp_client_->decryptIv()));
        }
        break;

        default:
            LOG(LS_WARNING) << "Unknown encryption method: " << srp_client_->method();
            break;
    }

    if (!cryptor_)
    {
        LOG(LS_WARNING) << "Unable to create cryptor";
        emit errorOccurred(Error::UNKNOWN);
        return;
    }

    QByteArray session_challenge_buffer;
    session_challenge_buffer.resize(cryptor_->decryptedDataSize(buffer.size()));

    if (!cryptor_->decrypt(buffer.constData(), buffer.size(), session_challenge_buffer.data()))
    {
        emit errorOccurred(Error::AUTHENTICATION_FAILURE);
        return;
    }

    proto::SessionChallenge session_challenge;
    if (!session_challenge.ParseFromArray(session_challenge_buffer.constData(),
                                          session_challenge_buffer.size()))
    {
        emit errorOccurred(Error::AUTHENTICATION_FAILURE);
        return;
    }

    if (!(session_challenge.session_types() & session_type_))
    {
        emit errorOccurred(Error::SESSION_TYPE_NOT_ALLOWED);
        return;
    }

    const proto::Version& host_version = session_challenge.version();

    peer_version_ = base::Version(
        host_version.major(), host_version.minor(), host_version.patch());

    proto::SessionResponse session_response;
    session_response.set_session_type(session_type_);

    proto::Version* client_version = session_response.mutable_version();
    client_version->set_major(ASPIA_VERSION_MAJOR);
    client_version->set_minor(ASPIA_VERSION_MINOR);
    client_version->set_patch(ASPIA_VERSION_PATCH);

    QByteArray session_response_buffer = serializeMessage(session_response);
    if (session_response_buffer.isEmpty())
    {
        LOG(LS_WARNING) << "Error when creating session response";
        emit errorOccurred(Error::UNKNOWN);
        return;
    }

    QByteArray encrypted_buffer;
    encrypted_buffer.resize(cryptor_->encryptedDataSize(session_response_buffer.size()));

    if (!cryptor_->encrypt(session_response_buffer.constData(),
                           session_response_buffer.size(),
                           encrypted_buffer.data()))
    {
        emit errorOccurred(Error::ENCRYPTION_FAILURE);
        return;
    }

    // After the successful completion of the key exchange, we pause the channel.
    // To continue receiving messages, slot |start| must be called.
    pause();

    key_exchange_state_ = KeyExchangeState::DONE;
    sendInternal(encrypted_buffer);
}

} // namespace net
<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 * $Log$
 * Revision 1.11  2003/12/11 16:01:12  strk
 * made buffer operation return a cloned input geom when called with 0 as distance
 *
 * Revision 1.10  2003/11/07 17:51:02  strk
 * Memory leak fix in insertEdge()
 *
 * Revision 1.9  2003/11/07 01:23:42  pramsey
 * Add standard CVS headers licence notices and copyrights to all cpp and h
 * files.
 *
 * Revision 1.8  2003/11/06 18:47:55  strk
 * Added throw specification for BufferOp's ::buildSubgraphs()
 * and ::computeBuffer(). Cleanup on exception in computeBuffer().
 *
 * Revision 1.7  2003/11/06 18:00:15  strk
 * Cleanup on exception in ::bufferOp()
 *
 * Revision 1.6  2003/10/15 16:39:03  strk
 * Made Edge::getCoordinates() return a 'const' value. Adapted code set.
 *
 **********************************************************************/

#include "../../headers/opBuffer.h"
#include <algorithm>

namespace geos {

Geometry* BufferOp::bufferOp(Geometry *g, double distance){

	if ( ! distance ) return g->clone();

	BufferOp *gBuf=new BufferOp(g);
	Geometry *geomBuf;
	try {
		geomBuf=gBuf->getResultGeometry(distance);
	}
	catch (...) {
		delete gBuf;
		throw;
	}
	delete gBuf;
	return geomBuf;
}

Geometry* BufferOp::bufferOp(Geometry *g, double distance, int quadrantSegments){
	if ( ! distance ) return g->clone();

	BufferOp *gBuf=new BufferOp(g);
	Geometry *geomBuf;
	try {
		geomBuf=gBuf->getResultGeometry(distance, quadrantSegments);
	}
	catch (...) {
		delete gBuf;
		throw;
	}
	delete gBuf;
	return geomBuf;
}

/**
*Compute the change in depth as an edge is crossed from R to L
*/
int BufferOp::depthDelta(Label *label){
	int lLoc=label->getLocation(0,Position::LEFT);
	int rLoc=label->getLocation(0,Position::RIGHT);
	if (lLoc==Location::INTERIOR && rLoc==Location::EXTERIOR)
		return 1;
	else if (lLoc==Location::EXTERIOR && rLoc==Location::INTERIOR)
		return -1;
	return 0;
}

BufferOp::BufferOp(Geometry *g0): GeometryGraphOperation(g0) {
	resultGeom=NULL;
	edgeList=new EdgeList();
	graph=new PlanarGraph(new OverlayNodeFactory());
	geomFact=new GeometryFactory(g0->getPrecisionModel(),g0->getSRID());
}

BufferOp::~BufferOp(){
	delete edgeList;
	delete graph;
	delete geomFact;
}

Geometry* BufferOp::getResultGeometry(double distance) {
	computeBuffer(distance,BufferLineBuilder::DEFAULT_QUADRANT_SEGMENTS);
	return resultGeom;
}

Geometry* BufferOp::getResultGeometry(double distance, int quadrantSegments) {
	computeBuffer(distance, quadrantSegments);
	return resultGeom;
}

void BufferOp::computeBuffer(double distance, int quadrantSegments) throw(TopologyException *) {
	BufferEdgeBuilder *bufEdgeBuilder=new BufferEdgeBuilder(cga,li,distance,resultPrecisionModel,quadrantSegments);
	vector<Edge*> *bufferEdgeList=bufEdgeBuilder->getEdges(getArgGeometry(0));
	vector<Edge*> *nodedEdges=nodeEdges(bufferEdgeList);
	for(int i=0;i<(int)nodedEdges->size();i++) {
		Edge *e=(*nodedEdges)[i];
		insertEdge(e);
	}
	replaceCollapsedEdges();
	graph->addEdges(edgeList);

	vector<BufferSubgraph*> *subgraphList=createSubgraphs();
	PolygonBuilder *polyBuilder=new PolygonBuilder(geomFact,cga);

	try {
		buildSubgraphs(subgraphList,polyBuilder);
	}
	// *Should* throw a TopologyException only
	catch (...)
	{
		delete polyBuilder;
		delete nodedEdges;
		delete bufEdgeBuilder;
		for(int i=0;i<(int)subgraphList->size();i++) {
			delete (*subgraphList)[i];
		}
		delete subgraphList;
		throw;
	}
	vector<Polygon*> *resultPolyList=polyBuilder->getPolygons();
	resultGeom=computeGeometry(resultPolyList);
	//computeBufferLine(graph);
	delete bufEdgeBuilder;
	delete polyBuilder;
	delete resultPolyList;
	for(int i=0;i<(int)subgraphList->size();i++) {
		delete (*subgraphList)[i];
	}
	delete subgraphList;
	delete nodedEdges;
}

/**
*Use a GeometryGraph to node the created edges,
*and create split edges between the nodes
*/
vector<Edge*>* BufferOp::nodeEdges(vector<Edge*> *edges){
	// intersect edges again to ensure they are noded correctly
	GeometryGraph *ggraph=new GeometryGraph(0,geomFact->getPrecisionModel(),0);
	for (int i=0;i<(int)edges->size();i++) {
		Edge *e=(*edges)[i];
		ggraph->addEdge(e);
	}
	SegmentIntersector *si=ggraph->computeSelfNodes(li, false);
	/*
	if (si.hasProperIntersection())
	Debug.println("proper intersection found");
	else
	Debug.println("no proper intersection found");
	*/
	vector<Edge*> *newEdges=new vector<Edge*>();
	ggraph->computeSplitEdges(newEdges);
	delete si;
	delete ggraph;
	return newEdges;
}
/**
*Inserted edges are checked identical edge already exists.
*If so, the edge is not inserted, but its label is merged
*with the existing edge.
* NOTE: the edge is deleted if already found !
*/
void BufferOp::insertEdge(Edge *e){
	//Debug.println(e);
	int foundIndex=edgeList->findEdgeIndex(e);
	// If an identical edge already exists, simply update its label
	if (foundIndex>=0) {
		Edge *existingEdge=(*edgeList)[foundIndex];
		Label *existingLabel=existingEdge->getLabel();
		Label *labelToMerge=e->getLabel();
		// check if new edge is in reverse direction to existing edge
		// if so, must flip the label before merging it
		if (!existingEdge->isPointwiseEqual(e)) {
			labelToMerge=new Label(e->getLabel());
			labelToMerge->flip();
		}
		existingLabel->merge(labelToMerge);
		// compute new depth delta of sum of edges
		int mergeDelta=depthDelta(labelToMerge);
		int existingDelta=existingEdge->getDepthDelta();
		int newDelta=existingDelta+mergeDelta;
		existingEdge->setDepthDelta(newDelta);
		checkDimensionalCollapse(labelToMerge,existingLabel);
		//Debug.print("new edge "); Debug.println(e);
		//Debug.print("existing "); Debug.println(existingEdge);
		delete e;
	} else {   // no matching existing edge was found
		// add this new edge to the list of edges in this graph
		//e.setName(name+edges.size());
		edgeList->push_back(e);
		e->setDepthDelta(depthDelta(e->getLabel()));
	}
}

/**
*If either of the GeometryLocations for the existing label is
*exactly opposite to the one in the labelToMerge,
*this indicates a dimensional collapse has happened.
*In this case, convert the label for that Geometry to a Line label
*/
void BufferOp::checkDimensionalCollapse(Label *labelToMerge,Label *existingLabel){
	if (existingLabel->isArea() && labelToMerge->isArea()) {
		for (int i=0;i<2;i++) {
			if (!labelToMerge->isNull(i)
				&&  labelToMerge->getLocation(i,Position::LEFT)==existingLabel->getLocation(i,Position::RIGHT)
				&&  labelToMerge->getLocation(i,Position::RIGHT)==existingLabel->getLocation(i,Position::LEFT)) {
					existingLabel->toLine(i);
			}
		}
	}
}

/**
*If collapsed edges are found, replace them with a new edge which is a L edge
*/
void BufferOp::replaceCollapsedEdges() {
	vector<Edge*> *newEdges=new vector<Edge*>();
	for(int i=0;i<(int)edgeList->size();i++) {
		Edge *e=(*edgeList)[i];
		if (e->isCollapsed()) {
			//Debug.print(e);
			edgeList->erase(edgeList->begin()+i);
			newEdges->push_back(e->getCollapsedEdge());
		}
	}
	((vector<Edge*>*)edgeList)->insert(edgeList->end(),newEdges->begin(),newEdges->end());
	delete newEdges;
}

bool bsgGreaterThan(BufferSubgraph *first,BufferSubgraph *second) {
	if (first->compareTo(second)>0)
		return true;
	else
		return false;
}

vector<BufferSubgraph*>* BufferOp::createSubgraphs(){
	vector<BufferSubgraph*> *subgraphList=new vector<BufferSubgraph*>();
	map<Coordinate,Node*,CoordLT> *nodeMap=graph->getNodeMap()->nodeMap;
	map<Coordinate,Node*,CoordLT>::iterator	it=nodeMap->begin();
	for (;it!=nodeMap->end();it++) {
		Node *node=it->second;
		if (!node->isVisited()) {
			BufferSubgraph *subgraph=new BufferSubgraph(cga);
			subgraph->create(node);
			subgraphList->push_back(subgraph);
		}
	}
	/**
	*Sort the subgraphs in descending order of their rightmost coordinate.
	*This ensures that when the Polygons for the subgraphs are built,
	*subgraphs for shells will have been built before the subgraphs for
	*any holes they contain.
	*/
	sort(subgraphList->begin(),subgraphList->end(),bsgGreaterThan);
	return subgraphList;
}

void BufferOp::buildSubgraphs(vector<BufferSubgraph*> *subgraphList,PolygonBuilder *polyBuilder) throw (TopologyException *) {
	for(int i=0;i<(int)subgraphList->size();i++) {
		BufferSubgraph *subgraph=(*subgraphList)[i];
		Coordinate& p=subgraph->getRightmostCoordinate();
		int outsideDepth=0;
		if (polyBuilder->containsPoint(p))
			outsideDepth=1;
		subgraph->computeDepth(outsideDepth);
		subgraph->findResultEdges();
		// This might throw a TopologyException
		polyBuilder->add(subgraph->getDirectedEdges(),subgraph->getNodes());
	}
}

Geometry* BufferOp::computeGeometry(vector<Polygon*> *resultPolyList){
	vector<Geometry*> *geomList=new vector<Geometry*>();
	for(int i=0;i<(int)resultPolyList->size();i++) {
		geomList->push_back((*resultPolyList)[i]);
	}
	Geometry *g=geomFact->buildGeometry(geomList);
	delete geomList;
	return g;
}

/**
*toLineStrings converts a list of Edges to LineStrings.
*/
Geometry* BufferOp::toLineStrings(EdgeList *edges){
	vector<Geometry*> *geomList=new vector<Geometry*>();
	for(int i=0;i<(int)edges->size();i++) {
		Edge *e=(*edges)[i];
		const CoordinateList *pts=e->getCoordinates();
		LineString *line=geomFact->createLineString(pts);
		geomList->push_back(line);
	}
	Geometry *geom=geomFact->buildGeometry(geomList);
	return geom;
}
}

<commit_msg>made buffer(0) back to its *correct* semantic (empy collection)<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 * $Log$
 * Revision 1.12  2003/12/11 17:01:35  strk
 * made buffer(0) back to its *correct* semantic (empy collection)
 *
 * Revision 1.11  2003/12/11 16:01:12  strk
 * made buffer operation return a cloned input geom when called with 0 as distance
 *
 * Revision 1.10  2003/11/07 17:51:02  strk
 * Memory leak fix in insertEdge()
 *
 * Revision 1.9  2003/11/07 01:23:42  pramsey
 * Add standard CVS headers licence notices and copyrights to all cpp and h
 * files.
 *
 * Revision 1.8  2003/11/06 18:47:55  strk
 * Added throw specification for BufferOp's ::buildSubgraphs()
 * and ::computeBuffer(). Cleanup on exception in computeBuffer().
 *
 * Revision 1.7  2003/11/06 18:00:15  strk
 * Cleanup on exception in ::bufferOp()
 *
 * Revision 1.6  2003/10/15 16:39:03  strk
 * Made Edge::getCoordinates() return a 'const' value. Adapted code set.
 *
 **********************************************************************/

#include "../../headers/opBuffer.h"
#include <algorithm>

namespace geos {

Geometry* BufferOp::bufferOp(Geometry *g, double distance){

	BufferOp *gBuf=new BufferOp(g);
	Geometry *geomBuf;
	try {
		geomBuf=gBuf->getResultGeometry(distance);
	}
	catch (...) {
		delete gBuf;
		throw;
	}
	delete gBuf;
	return geomBuf;
}

Geometry* BufferOp::bufferOp(Geometry *g, double distance, int quadrantSegments){
	BufferOp *gBuf=new BufferOp(g);
	Geometry *geomBuf;
	try {
		geomBuf=gBuf->getResultGeometry(distance, quadrantSegments);
	}
	catch (...) {
		delete gBuf;
		throw;
	}
	delete gBuf;
	return geomBuf;
}

/**
*Compute the change in depth as an edge is crossed from R to L
*/
int BufferOp::depthDelta(Label *label){
	int lLoc=label->getLocation(0,Position::LEFT);
	int rLoc=label->getLocation(0,Position::RIGHT);
	if (lLoc==Location::INTERIOR && rLoc==Location::EXTERIOR)
		return 1;
	else if (lLoc==Location::EXTERIOR && rLoc==Location::INTERIOR)
		return -1;
	return 0;
}

BufferOp::BufferOp(Geometry *g0): GeometryGraphOperation(g0) {
	resultGeom=NULL;
	edgeList=new EdgeList();
	graph=new PlanarGraph(new OverlayNodeFactory());
	geomFact=new GeometryFactory(g0->getPrecisionModel(),g0->getSRID());
}

BufferOp::~BufferOp(){
	delete edgeList;
	delete graph;
	delete geomFact;
}

Geometry* BufferOp::getResultGeometry(double distance) {
	computeBuffer(distance,BufferLineBuilder::DEFAULT_QUADRANT_SEGMENTS);
	return resultGeom;
}

Geometry* BufferOp::getResultGeometry(double distance, int quadrantSegments) {
	computeBuffer(distance, quadrantSegments);
	return resultGeom;
}

void BufferOp::computeBuffer(double distance, int quadrantSegments) throw(TopologyException *) {
	BufferEdgeBuilder *bufEdgeBuilder=new BufferEdgeBuilder(cga,li,distance,resultPrecisionModel,quadrantSegments);
	vector<Edge*> *bufferEdgeList=bufEdgeBuilder->getEdges(getArgGeometry(0));
	vector<Edge*> *nodedEdges=nodeEdges(bufferEdgeList);
	for(int i=0;i<(int)nodedEdges->size();i++) {
		Edge *e=(*nodedEdges)[i];
		insertEdge(e);
	}
	replaceCollapsedEdges();
	graph->addEdges(edgeList);

	vector<BufferSubgraph*> *subgraphList=createSubgraphs();
	PolygonBuilder *polyBuilder=new PolygonBuilder(geomFact,cga);

	try {
		buildSubgraphs(subgraphList,polyBuilder);
	}
	// *Should* throw a TopologyException only
	catch (...)
	{
		delete polyBuilder;
		delete nodedEdges;
		delete bufEdgeBuilder;
		for(int i=0;i<(int)subgraphList->size();i++) {
			delete (*subgraphList)[i];
		}
		delete subgraphList;
		throw;
	}
	vector<Polygon*> *resultPolyList=polyBuilder->getPolygons();
	resultGeom=computeGeometry(resultPolyList);
	//computeBufferLine(graph);
	delete bufEdgeBuilder;
	delete polyBuilder;
	delete resultPolyList;
	for(int i=0;i<(int)subgraphList->size();i++) {
		delete (*subgraphList)[i];
	}
	delete subgraphList;
	delete nodedEdges;
}

/**
*Use a GeometryGraph to node the created edges,
*and create split edges between the nodes
*/
vector<Edge*>* BufferOp::nodeEdges(vector<Edge*> *edges){
	// intersect edges again to ensure they are noded correctly
	GeometryGraph *ggraph=new GeometryGraph(0,geomFact->getPrecisionModel(),0);
	for (int i=0;i<(int)edges->size();i++) {
		Edge *e=(*edges)[i];
		ggraph->addEdge(e);
	}
	SegmentIntersector *si=ggraph->computeSelfNodes(li, false);
	/*
	if (si.hasProperIntersection())
	Debug.println("proper intersection found");
	else
	Debug.println("no proper intersection found");
	*/
	vector<Edge*> *newEdges=new vector<Edge*>();
	ggraph->computeSplitEdges(newEdges);
	delete si;
	delete ggraph;
	return newEdges;
}
/**
*Inserted edges are checked identical edge already exists.
*If so, the edge is not inserted, but its label is merged
*with the existing edge.
* NOTE: the edge is deleted if already found !
*/
void BufferOp::insertEdge(Edge *e){
	//Debug.println(e);
	int foundIndex=edgeList->findEdgeIndex(e);
	// If an identical edge already exists, simply update its label
	if (foundIndex>=0) {
		Edge *existingEdge=(*edgeList)[foundIndex];
		Label *existingLabel=existingEdge->getLabel();
		Label *labelToMerge=e->getLabel();
		// check if new edge is in reverse direction to existing edge
		// if so, must flip the label before merging it
		if (!existingEdge->isPointwiseEqual(e)) {
			labelToMerge=new Label(e->getLabel());
			labelToMerge->flip();
		}
		existingLabel->merge(labelToMerge);
		// compute new depth delta of sum of edges
		int mergeDelta=depthDelta(labelToMerge);
		int existingDelta=existingEdge->getDepthDelta();
		int newDelta=existingDelta+mergeDelta;
		existingEdge->setDepthDelta(newDelta);
		checkDimensionalCollapse(labelToMerge,existingLabel);
		//Debug.print("new edge "); Debug.println(e);
		//Debug.print("existing "); Debug.println(existingEdge);
		delete e;
	} else {   // no matching existing edge was found
		// add this new edge to the list of edges in this graph
		//e.setName(name+edges.size());
		edgeList->push_back(e);
		e->setDepthDelta(depthDelta(e->getLabel()));
	}
}

/**
*If either of the GeometryLocations for the existing label is
*exactly opposite to the one in the labelToMerge,
*this indicates a dimensional collapse has happened.
*In this case, convert the label for that Geometry to a Line label
*/
void BufferOp::checkDimensionalCollapse(Label *labelToMerge,Label *existingLabel){
	if (existingLabel->isArea() && labelToMerge->isArea()) {
		for (int i=0;i<2;i++) {
			if (!labelToMerge->isNull(i)
				&&  labelToMerge->getLocation(i,Position::LEFT)==existingLabel->getLocation(i,Position::RIGHT)
				&&  labelToMerge->getLocation(i,Position::RIGHT)==existingLabel->getLocation(i,Position::LEFT)) {
					existingLabel->toLine(i);
			}
		}
	}
}

/**
*If collapsed edges are found, replace them with a new edge which is a L edge
*/
void BufferOp::replaceCollapsedEdges() {
	vector<Edge*> *newEdges=new vector<Edge*>();
	for(int i=0;i<(int)edgeList->size();i++) {
		Edge *e=(*edgeList)[i];
		if (e->isCollapsed()) {
			//Debug.print(e);
			edgeList->erase(edgeList->begin()+i);
			newEdges->push_back(e->getCollapsedEdge());
		}
	}
	((vector<Edge*>*)edgeList)->insert(edgeList->end(),newEdges->begin(),newEdges->end());
	delete newEdges;
}

bool bsgGreaterThan(BufferSubgraph *first,BufferSubgraph *second) {
	if (first->compareTo(second)>0)
		return true;
	else
		return false;
}

vector<BufferSubgraph*>* BufferOp::createSubgraphs(){
	vector<BufferSubgraph*> *subgraphList=new vector<BufferSubgraph*>();
	map<Coordinate,Node*,CoordLT> *nodeMap=graph->getNodeMap()->nodeMap;
	map<Coordinate,Node*,CoordLT>::iterator	it=nodeMap->begin();
	for (;it!=nodeMap->end();it++) {
		Node *node=it->second;
		if (!node->isVisited()) {
			BufferSubgraph *subgraph=new BufferSubgraph(cga);
			subgraph->create(node);
			subgraphList->push_back(subgraph);
		}
	}
	/**
	*Sort the subgraphs in descending order of their rightmost coordinate.
	*This ensures that when the Polygons for the subgraphs are built,
	*subgraphs for shells will have been built before the subgraphs for
	*any holes they contain.
	*/
	sort(subgraphList->begin(),subgraphList->end(),bsgGreaterThan);
	return subgraphList;
}

void BufferOp::buildSubgraphs(vector<BufferSubgraph*> *subgraphList,PolygonBuilder *polyBuilder) throw (TopologyException *) {
	for(int i=0;i<(int)subgraphList->size();i++) {
		BufferSubgraph *subgraph=(*subgraphList)[i];
		Coordinate& p=subgraph->getRightmostCoordinate();
		int outsideDepth=0;
		if (polyBuilder->containsPoint(p))
			outsideDepth=1;
		subgraph->computeDepth(outsideDepth);
		subgraph->findResultEdges();
		// This might throw a TopologyException
		polyBuilder->add(subgraph->getDirectedEdges(),subgraph->getNodes());
	}
}

Geometry* BufferOp::computeGeometry(vector<Polygon*> *resultPolyList){
	vector<Geometry*> *geomList=new vector<Geometry*>();
	for(int i=0;i<(int)resultPolyList->size();i++) {
		geomList->push_back((*resultPolyList)[i]);
	}
	Geometry *g=geomFact->buildGeometry(geomList);
	delete geomList;
	return g;
}

/**
*toLineStrings converts a list of Edges to LineStrings.
*/
Geometry* BufferOp::toLineStrings(EdgeList *edges){
	vector<Geometry*> *geomList=new vector<Geometry*>();
	for(int i=0;i<(int)edges->size();i++) {
		Edge *e=(*edges)[i];
		const CoordinateList *pts=e->getCoordinates();
		LineString *line=geomFact->createLineString(pts);
		geomList->push_back(line);
	}
	Geometry *geom=geomFact->buildGeometry(geomList);
	return geom;
}
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: basenode.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2005-10-11 08:43:44 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef INCLUDED_SLIDESHOW_BASENODE_HXX
#define INCLUDED_SLIDESHOW_BASENODE_HXX

#include "animationnode.hxx"
#include "slideshowcontext.hxx"
#include "shapesubset.hxx"
#include <vector>

namespace presentation {
namespace internal {

typedef int StateTransitionTable[17];

/** Context for every node.

    Besides the global AnimationNodeFactory::Context data,
    this struct also contains the current DocTree subset
    for this node. If start and end index of the
    DocTreeNode are equal, the node should use the
    complete shape.
*/
struct NodeContext
{
    NodeContext( const SlideShowContext& rContext )
        : maContext( rContext ),
          mpMasterShapeSubset(),
          mnStartDelay(0.0),
          mbIsIndependentSubset( true )
        {}

    void dispose() { maContext.dispose(); }

    /// Context as passed to createAnimationNode()
    SlideShowContext        maContext;

    /// Shape to be used (provided by parent, e.g. for iterations)
    ShapeSubsetSharedPtr    mpMasterShapeSubset;

    /// Additional delay to node begin (to offset iterate effects)
    double                  mnStartDelay;

    /// When true, subset must be created during slide initialization
    bool                    mbIsIndependentSubset;
};

class BaseContainerNode;

/** This interface extends AnimationNode with some
    file-private accessor methods.
*/
class BaseNode : public AnimationNode
{
public:
    BaseNode( const ::com::sun::star::uno::Reference<
              ::com::sun::star::animations::XAnimationNode >&     xNode,
              const ::boost::shared_ptr< BaseContainerNode >&     rParent,
              const NodeContext&                                  rContext );

    /** Provide the node with a shared_ptr to itself.

        Since implementation has to create objects which need
        a shared_ptr to this node, and a pointee cannot
        retrieve a shared_ptr to itself internally, have to
        set that from the outside.
    */
    void setSelf( const ::boost::shared_ptr< BaseNode >& rSelf );

    // Disposable interface
    // --------------------

    virtual void dispose();

    // Implemented subset of AnimationNode interface
    // ---------------------------------------------
    virtual ::com::sun::star::uno::Reference<
        ::com::sun::star::animations::XAnimationNode> getXAnimationNode() const;

    virtual bool init();
    virtual bool resolve();
    virtual bool activate();
    virtual void deactivate();
    virtual void end();
    virtual NodeState getState() const;
    virtual bool registerDeactivatingListener(
        const AnimationNodeSharedPtr& rNotifee );

#if defined(VERBOSE) && defined(DBG_UTIL)
    virtual void showState() const;
    virtual const char* getDescription() const;
    void showTreeFromWithin() const;
#endif

    const ::boost::shared_ptr< BaseContainerNode >& getParentNode() const
        { return mpParent; }

protected:
    // inline accessors
    // ----------------

    const SlideShowContext& getContext() const { return maContext; }
    const ::boost::shared_ptr< BaseNode >& getSelf() const { return mpSelf; }
    const ::com::sun::star::uno::Reference<
        ::com::sun::star::animations::XAnimationNode >& getXNode() const
        { return mxNode; }

    bool isMainSequenceRootNode() const { return mbIsMainSequenceRootNode; }

    /** Schedule event that activates the node, once it is resolved

        You can override this method in derived
        classes. AnimateBaseNode does it to implement its
        fixed delay
    */
    virtual void scheduleActivationEvent();

    /** Schedule event that deactivates the node, once it is active

        You can override this method in derived classes.
    */
    virtual void scheduleDeactivationEvent() const;

private:

    /** Get the default fill mode.

        If this node's default mode is AnimationFill::DEFAULT,
        this method recursively calls the parent node.
    */
    sal_Int16 getFillDefaultMode() const;

    /** Get the default restart mode

        If this node's default mode is
        AnimationRestart::DEFAULT, this method recursively
        calls the parent node.
    */
    sal_Int16 getRestartDefaultMode() const;

    /// Get the node's restart mode
    sal_Int16 getRestartMode();

    /// Get the node's fill mode
    sal_Int16 getFillMode();

private:
    SlideShowContext                                   maContext;

    typedef ::std::vector< AnimationNodeSharedPtr >    ListenerVector;

    ListenerVector                                     maDeactivatingListeners;
    ::com::sun::star::uno::Reference<
        ::com::sun::star::animations::XAnimationNode > mxNode;
    ::boost::shared_ptr< BaseContainerNode >           mpParent;
    ::boost::shared_ptr< BaseNode >                    mpSelf;
    const int*                                         mpStateTransitionTable;
    const double                                       mnStartDelay;
    AnimationNode::NodeState                           meCurrState;
    const bool                                         mbIsMainSequenceRootNode;
};

typedef ::boost::shared_ptr< BaseNode > BaseNodeSharedPtr;

} // namespace internal
} // namespace presentation

#endif /* INCLUDED_SLIDESHOW_BASENODE_HXX */

<commit_msg>INTEGRATION: CWS presfixes10 (1.6.6); FILE MERGED 2005/11/10 15:50:01 dbo 1.6.6.3: missing friend decl for SunCC Issue number: Submitted by: Reviewed by: 2005/11/10 14:57:26 dbo 1.6.6.2: #i45197# cleanup Issue number: Submitted by: Reviewed by: 2005/11/07 15:26:53 dbo 1.6.6.1: #i45197# revised code Issue number: Submitted by: Reviewed by:<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: basenode.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2006-07-26 07:35:12 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef INCLUDED_SLIDESHOW_BASENODE_HXX
#define INCLUDED_SLIDESHOW_BASENODE_HXX

#include "canvas/debug.hxx"
#include "osl/diagnose.hxx"
#include "animationnode.hxx"
#include "slideshowcontext.hxx"
#include "shapesubset.hxx"
#include "boost/noncopyable.hpp"
#include <vector>

namespace presentation {
namespace internal {

/** Context for every node.

    Besides the global AnimationNodeFactory::Context data,
    this struct also contains the current DocTree subset
    for this node. If start and end index of the
    DocTreeNode are equal, the node should use the
    complete shape.
*/
struct NodeContext
{
    NodeContext( const SlideShowContext& rContext )
        : maContext( rContext ),
          mpMasterShapeSubset(),
          mnStartDelay(0.0),
          mbIsIndependentSubset( true )
        {}

    void dispose() { maContext.dispose(); }

    /// Context as passed to createAnimationNode()
    SlideShowContext        maContext;

    /// Shape to be used (provided by parent, e.g. for iterations)
    ShapeSubsetSharedPtr    mpMasterShapeSubset;

    /// Additional delay to node begin (to offset iterate effects)
    double                  mnStartDelay;

    /// When true, subset must be created during slide initialization
    bool                    mbIsIndependentSubset;
};

class BaseContainerNode;

/** This interface extends AnimationNode with some
    file-private accessor methods.
*/
class BaseNode : public AnimationNode,
                 private ::osl::DebugBase<BaseNode>,
                 private ::boost::noncopyable
{
public:
    BaseNode( ::com::sun::star::uno::Reference<
              ::com::sun::star::animations::XAnimationNode> const& xNode,
              ::boost::shared_ptr<BaseContainerNode> const& pParent,
              NodeContext const& rContext );

    /** Provide the node with a shared_ptr to itself.

        Since implementation has to create objects which need
        a shared_ptr to this node, and a pointee cannot
        retrieve a shared_ptr to itself internally, have to
        set that from the outside.
    */
    void setSelf( const ::boost::shared_ptr< BaseNode >& rSelf );

#if defined(VERBOSE) && defined(DBG_UTIL)
    virtual void showState() const;
    virtual const char* getDescription() const;
    void showTreeFromWithin() const;
#endif

    const ::boost::shared_ptr< BaseContainerNode >& getParentNode() const
        { return mpParent; }

    // Disposable:
    virtual void dispose();

    // AnimationNode:
    virtual bool init();
    virtual bool resolve();
    virtual bool activate();
    virtual void deactivate();
    virtual void end();
    virtual ::com::sun::star::uno::Reference<
        ::com::sun::star::animations::XAnimationNode> getXAnimationNode() const;
    virtual NodeState getState() const;
    virtual bool registerDeactivatingListener(
        const AnimationNodeSharedPtr& rNotifee );
    // nop:
    virtual void notifyDeactivating( const AnimationNodeSharedPtr& rNotifier );

protected:
    void scheduleDeactivationEvent( EventSharedPtr const& pEvent =
                                    EventSharedPtr() );

    SlideShowContext const& getContext() const { return maContext; }

    ::boost::shared_ptr<BaseNode> const& getSelf() const { return mpSelf; }

    bool isMainSequenceRootNode() const { return mbIsMainSequenceRootNode; }

    bool checkValidNode() const {
        ENSURE_AND_THROW( mpSelf, "no self ptr set!" );
        bool const bRet = (meCurrState != INVALID);
        OSL_ENSURE( bRet, "### INVALID node!" );
        return bRet;
    }

private:
    // all state affecting methods have "_st" counterparts being called at
    // derived classes when in state transistion: no-ops here at BaseNode...
    virtual bool init_st();
    virtual bool resolve_st();
    virtual void activate_st();
    virtual void deactivate_st( NodeState eDestState );

private:
    /// notifies
    /// - all registered deactivation listeners
    /// - single animation end (every node)
    /// - slide animations (if main sequence root node)
    void notifyEndListeners() const;

    /// Get the node's restart mode
    sal_Int16 getRestartMode();

    /** Get the default restart mode

        If this node's default mode is
        AnimationRestart::DEFAULT, this method recursively
        calls the parent node.
    */
    sal_Int16 getRestartDefaultMode() const;

    /// Get the node's fill mode
    sal_Int16 getFillMode();

    /** Get the default fill mode.

        If this node's default mode is AnimationFill::DEFAULT,
        this method recursively calls the parent node.
    */
    sal_Int16 getFillDefaultMode() const;

    bool isTransition( NodeState eFromState, NodeState eToState,
                       bool debugAssert = true ) const {
        bool const bRet =((mpStateTransitionTable[eFromState] & eToState) != 0);
        OSL_ENSURE( !debugAssert || bRet, "### state unreachable!" );
        return bRet;
    }

    bool inStateOrTransition( int mask ) const {
        return ((meCurrState & mask) != 0 ||
                (meCurrentStateTransition & mask) != 0);
    }

    class StateTransition;
    friend class StateTransition;

private:
    SlideShowContext                                   maContext;

    typedef ::std::vector< AnimationNodeSharedPtr >    ListenerVector;

    ListenerVector                                     maDeactivatingListeners;
    ::com::sun::star::uno::Reference<
        ::com::sun::star::animations::XAnimationNode > mxAnimationNode;
    ::boost::shared_ptr< BaseContainerNode >           mpParent;
    ::boost::shared_ptr< BaseNode >                    mpSelf;
    const int*                                         mpStateTransitionTable;
    const double                                       mnStartDelay;
    NodeState                                          meCurrState;
    int                                                meCurrentStateTransition;
    EventSharedPtr                                     mpCurrentEvent;
    const bool                                         mbIsMainSequenceRootNode;
};

typedef ::boost::shared_ptr< BaseNode > BaseNodeSharedPtr;

} // namespace internal
} // namespace presentation

#endif /* INCLUDED_SLIDESHOW_BASENODE_HXX */

<|endoftext|>


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

#include <vcl/outdev.hxx>
#include <vcl/window.hxx>

#include <vcl/salnativewidgets.hxx>
#include <vcl/pdfextoutdevdata.hxx>

#include <salgdi.hxx>

static bool EnableNativeWidget( const OutputDevice& i_rDevice )
{
    const OutDevType eType( i_rDevice.GetOutDevType() );
    switch ( eType )
    {

    case OUTDEV_WINDOW:
        return dynamic_cast< const Window* >( &i_rDevice )->IsNativeWidgetEnabled();

    case OUTDEV_VIRDEV:
    {
        const ::vcl::ExtOutDevData* pOutDevData( i_rDevice.GetExtOutDevData() );
        const ::vcl::PDFExtOutDevData* pPDFData( dynamic_cast< const ::vcl::PDFExtOutDevData* >( pOutDevData ) );
        if ( pPDFData != NULL )
            return false;
        return true;
    }

    default:
        return false;
    }
}

ImplControlValue::~ImplControlValue()
{
}

ImplControlValue* ImplControlValue::clone() const
{
    assert( typeid( const ImplControlValue ) == typeid( *this ));
    return new ImplControlValue( *this );
}

ScrollbarValue::~ScrollbarValue()
{
}

ScrollbarValue* ScrollbarValue::clone() const
{
    assert( typeid( const ScrollbarValue ) == typeid( *this ));
    return new ScrollbarValue( *this );
}

SliderValue::~SliderValue()
{
}

SliderValue* SliderValue::clone() const
{
    assert( typeid( const SliderValue ) == typeid( *this ));
    return new SliderValue( *this );
}

TabitemValue::~TabitemValue()
{
}

TabitemValue* TabitemValue::clone() const
{
    assert( typeid( const TabitemValue ) == typeid( *this ));
    return new TabitemValue( *this );
}

SpinbuttonValue::~SpinbuttonValue()
{
}

SpinbuttonValue* SpinbuttonValue::clone() const
{
    assert( typeid( const SpinbuttonValue ) == typeid( *this ));
    return new SpinbuttonValue( *this );
}

ToolbarValue::~ToolbarValue()
{
}

ToolbarValue* ToolbarValue::clone() const
{
    assert( typeid( const ToolbarValue ) == typeid( *this ));
    return new ToolbarValue( *this );
}

MenubarValue::~MenubarValue()
{
}

MenubarValue* MenubarValue::clone() const
{
    assert( typeid( const MenubarValue ) == typeid( *this ));
    return new MenubarValue( *this );
}

MenupopupValue::~MenupopupValue()
{
}

MenupopupValue* MenupopupValue::clone() const
{
    assert( typeid( const MenupopupValue ) == typeid( *this ));
    return new MenupopupValue( *this );
}

PushButtonValue::~PushButtonValue()
{
}

PushButtonValue* PushButtonValue::clone() const
{
    assert( typeid( const PushButtonValue ) == typeid( *this ));
    return new PushButtonValue( *this );
}

// These functions are mainly passthrough functions that allow access to
// the SalFrame behind a Window object for native widget rendering purposes.

bool OutputDevice::IsNativeControlSupported( ControlType nType, ControlPart nPart ) const
{
    if( !EnableNativeWidget( *this ) )
        return false;

    if ( !mpGraphics )
        if ( !AcquireGraphics() )
            return false;

    return( mpGraphics->IsNativeControlSupported(nType, nPart) );
}

bool OutputDevice::HitTestNativeControl( ControlType nType,
                              ControlPart nPart,
                              const Rectangle& rControlRegion,
                              const Point& aPos,
                              bool& rIsInside ) const
{
    if( !EnableNativeWidget( *this ) )
        return false;

    if ( !mpGraphics )
        if ( !AcquireGraphics() )
            return false;

    Point aWinOffs( mnOutOffX, mnOutOffY );
    Rectangle screenRegion( rControlRegion );
    screenRegion.Move( aWinOffs.X(), aWinOffs.Y());

    return( mpGraphics->HitTestNativeControl(nType, nPart, screenRegion, Point( aPos.X() + mnOutOffX, aPos.Y() + mnOutOffY ),
        rIsInside, this ) );
}

static boost::shared_ptr< ImplControlValue > TransformControlValue( const ImplControlValue& rVal, const OutputDevice& rDev )
{
    boost::shared_ptr< ImplControlValue > aResult;
    switch( rVal.getType() )
    {
    case CTRL_SLIDER:
        {
            const SliderValue* pSlVal = static_cast<const SliderValue*>(&rVal);
            SliderValue* pNew = new SliderValue( *pSlVal );
            aResult.reset( pNew );
            pNew->maThumbRect = rDev.ImplLogicToDevicePixel( pSlVal->maThumbRect );
        }
        break;
    case CTRL_SCROLLBAR:
        {
            const ScrollbarValue* pScVal = static_cast<const ScrollbarValue*>(&rVal);
            ScrollbarValue* pNew = new ScrollbarValue( *pScVal );
            aResult.reset( pNew );
            pNew->maThumbRect = rDev.ImplLogicToDevicePixel( pScVal->maThumbRect );
            pNew->maButton1Rect = rDev.ImplLogicToDevicePixel( pScVal->maButton1Rect );
            pNew->maButton2Rect = rDev.ImplLogicToDevicePixel( pScVal->maButton2Rect );
        }
        break;
    case CTRL_SPINBUTTONS:
        {
            const SpinbuttonValue* pSpVal = static_cast<const SpinbuttonValue*>(&rVal);
            SpinbuttonValue* pNew = new SpinbuttonValue( *pSpVal );
            aResult.reset( pNew );
            pNew->maUpperRect = rDev.ImplLogicToDevicePixel( pSpVal->maUpperRect );
            pNew->maLowerRect = rDev.ImplLogicToDevicePixel( pSpVal->maLowerRect );
        }
        break;
    case CTRL_TOOLBAR:
        {
            const ToolbarValue* pTVal = static_cast<const ToolbarValue*>(&rVal);
            ToolbarValue* pNew = new ToolbarValue( *pTVal );
            aResult.reset( pNew );
            pNew->maGripRect = rDev.ImplLogicToDevicePixel( pTVal->maGripRect );
        }
        break;
    case CTRL_TAB_ITEM:
        {
            const TabitemValue* pTIVal = static_cast<const TabitemValue*>(&rVal);
            TabitemValue* pNew = new TabitemValue( *pTIVal );
            aResult.reset( pNew );
        }
        break;
    case CTRL_MENUBAR:
        {
            const MenubarValue* pMVal = static_cast<const MenubarValue*>(&rVal);
            MenubarValue* pNew = new MenubarValue( *pMVal );
            aResult.reset( pNew );
        }
        break;
    case CTRL_PUSHBUTTON:
        {
            const PushButtonValue* pBVal = static_cast<const PushButtonValue*>(&rVal);
            PushButtonValue* pNew = new PushButtonValue( *pBVal );
            aResult.reset( pNew );
        }
        break;
    case CTRL_GENERIC:
            aResult.reset( new ImplControlValue( rVal ) );
            break;
    case CTRL_MENU_POPUP:
        {
            const MenupopupValue* pMVal = static_cast<const MenupopupValue*>(&rVal);
            MenupopupValue* pNew = new MenupopupValue( *pMVal );
            pNew->maItemRect = rDev.ImplLogicToDevicePixel( pMVal->maItemRect );
            aResult.reset( pNew );
        }
        break;
    default:
        OSL_FAIL( "unknown ImplControlValue type !" );
        break;
    }
    return aResult;
}
bool OutputDevice::DrawNativeControl( ControlType nType,
                            ControlPart nPart,
                            const Rectangle& rControlRegion,
                            ControlState nState,
                            const ImplControlValue& aValue,
                            const OUString& aCaption )
{
    if( !EnableNativeWidget( *this ) )
        return false;

    // make sure the current clip region is initialized correctly
    if ( !mpGraphics )
        if ( !AcquireGraphics() )
            return false;

    if ( mbInitClipRegion )
        InitClipRegion();
    if ( mbOutputClipped )
        return true;

    if ( mbInitLineColor )
        InitLineColor();
    if ( mbInitFillColor )
        InitFillColor();

    // Convert the coordinates from relative to Window-absolute, so we draw
    // in the correct place in platform code
    boost::shared_ptr< ImplControlValue > aScreenCtrlValue( TransformControlValue( aValue, *this ) );
    Rectangle screenRegion( ImplLogicToDevicePixel( rControlRegion ) );

    Region aTestRegion( GetActiveClipRegion() );
    aTestRegion.Intersect( rControlRegion );
    if (aTestRegion == Region(rControlRegion))
        nState |= CTRL_CACHING_ALLOWED;   // control is not clipped, caching allowed

    bool bRet = mpGraphics->DrawNativeControl(nType, nPart, screenRegion, nState, *aScreenCtrlValue, aCaption, this );

    return bRet;
}

bool OutputDevice::GetNativeControlRegion(  ControlType nType,
                                ControlPart nPart,
                                const Rectangle& rControlRegion,
                                ControlState nState,
                                const ImplControlValue& aValue,
                                const OUString& aCaption,
                                Rectangle &rNativeBoundingRegion,
                                Rectangle &rNativeContentRegion ) const
{
    if( !EnableNativeWidget( *this ) )
        return false;

    if ( !mpGraphics )
        if ( !AcquireGraphics() )
            return false;

    // Convert the coordinates from relative to Window-absolute, so we draw
    // in the correct place in platform code
    boost::shared_ptr< ImplControlValue > aScreenCtrlValue( TransformControlValue( aValue, *this ) );
    Rectangle screenRegion( ImplLogicToDevicePixel( rControlRegion ) );

    bool bRet = mpGraphics->GetNativeControlRegion(nType, nPart, screenRegion, nState, *aScreenCtrlValue,
                                aCaption, rNativeBoundingRegion,
                                rNativeContentRegion, this );
    if( bRet )
    {
        // transform back native regions
        rNativeBoundingRegion = ImplDevicePixelToLogic( rNativeBoundingRegion );
        rNativeContentRegion = ImplDevicePixelToLogic( rNativeContentRegion );
    }

    return bRet;
}

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

#include <vcl/outdev.hxx>
#include <vcl/window.hxx>

#include <vcl/salnativewidgets.hxx>
#include <vcl/pdfextoutdevdata.hxx>

#include <salgdi.hxx>

static bool EnableNativeWidget( const OutputDevice& i_rDevice )
{
    const OutDevType eType( i_rDevice.GetOutDevType() );
    switch ( eType )
    {

    case OUTDEV_WINDOW:
        {
            const Window* pWindow = dynamic_cast< const Window* >( &i_rDevice );
            if (pWindow)
            {
                return pWindow->IsNativeWidgetEnabled();
            }
            else
            {
                SAL_WARN ("vcl.gdi", "Could not cast i_rDevice to Window");
                assert (pWindow);
                return false;
            }
        }

    case OUTDEV_VIRDEV:
    {
        const ::vcl::ExtOutDevData* pOutDevData( i_rDevice.GetExtOutDevData() );
        const ::vcl::PDFExtOutDevData* pPDFData( dynamic_cast< const ::vcl::PDFExtOutDevData* >( pOutDevData ) );
        if ( pPDFData != NULL )
            return false;
        return true;
    }

    default:
        return false;
    }
}

ImplControlValue::~ImplControlValue()
{
}

ImplControlValue* ImplControlValue::clone() const
{
    assert( typeid( const ImplControlValue ) == typeid( *this ));
    return new ImplControlValue( *this );
}

ScrollbarValue::~ScrollbarValue()
{
}

ScrollbarValue* ScrollbarValue::clone() const
{
    assert( typeid( const ScrollbarValue ) == typeid( *this ));
    return new ScrollbarValue( *this );
}

SliderValue::~SliderValue()
{
}

SliderValue* SliderValue::clone() const
{
    assert( typeid( const SliderValue ) == typeid( *this ));
    return new SliderValue( *this );
}

TabitemValue::~TabitemValue()
{
}

TabitemValue* TabitemValue::clone() const
{
    assert( typeid( const TabitemValue ) == typeid( *this ));
    return new TabitemValue( *this );
}

SpinbuttonValue::~SpinbuttonValue()
{
}

SpinbuttonValue* SpinbuttonValue::clone() const
{
    assert( typeid( const SpinbuttonValue ) == typeid( *this ));
    return new SpinbuttonValue( *this );
}

ToolbarValue::~ToolbarValue()
{
}

ToolbarValue* ToolbarValue::clone() const
{
    assert( typeid( const ToolbarValue ) == typeid( *this ));
    return new ToolbarValue( *this );
}

MenubarValue::~MenubarValue()
{
}

MenubarValue* MenubarValue::clone() const
{
    assert( typeid( const MenubarValue ) == typeid( *this ));
    return new MenubarValue( *this );
}

MenupopupValue::~MenupopupValue()
{
}

MenupopupValue* MenupopupValue::clone() const
{
    assert( typeid( const MenupopupValue ) == typeid( *this ));
    return new MenupopupValue( *this );
}

PushButtonValue::~PushButtonValue()
{
}

PushButtonValue* PushButtonValue::clone() const
{
    assert( typeid( const PushButtonValue ) == typeid( *this ));
    return new PushButtonValue( *this );
}

// These functions are mainly passthrough functions that allow access to
// the SalFrame behind a Window object for native widget rendering purposes.

bool OutputDevice::IsNativeControlSupported( ControlType nType, ControlPart nPart ) const
{
    if( !EnableNativeWidget( *this ) )
        return false;

    if ( !mpGraphics )
        if ( !AcquireGraphics() )
            return false;

    return( mpGraphics->IsNativeControlSupported(nType, nPart) );
}

bool OutputDevice::HitTestNativeControl( ControlType nType,
                              ControlPart nPart,
                              const Rectangle& rControlRegion,
                              const Point& aPos,
                              bool& rIsInside ) const
{
    if( !EnableNativeWidget( *this ) )
        return false;

    if ( !mpGraphics )
        if ( !AcquireGraphics() )
            return false;

    Point aWinOffs( mnOutOffX, mnOutOffY );
    Rectangle screenRegion( rControlRegion );
    screenRegion.Move( aWinOffs.X(), aWinOffs.Y());

    return( mpGraphics->HitTestNativeControl(nType, nPart, screenRegion, Point( aPos.X() + mnOutOffX, aPos.Y() + mnOutOffY ),
        rIsInside, this ) );
}

static boost::shared_ptr< ImplControlValue > TransformControlValue( const ImplControlValue& rVal, const OutputDevice& rDev )
{
    boost::shared_ptr< ImplControlValue > aResult;
    switch( rVal.getType() )
    {
    case CTRL_SLIDER:
        {
            const SliderValue* pSlVal = static_cast<const SliderValue*>(&rVal);
            SliderValue* pNew = new SliderValue( *pSlVal );
            aResult.reset( pNew );
            pNew->maThumbRect = rDev.ImplLogicToDevicePixel( pSlVal->maThumbRect );
        }
        break;
    case CTRL_SCROLLBAR:
        {
            const ScrollbarValue* pScVal = static_cast<const ScrollbarValue*>(&rVal);
            ScrollbarValue* pNew = new ScrollbarValue( *pScVal );
            aResult.reset( pNew );
            pNew->maThumbRect = rDev.ImplLogicToDevicePixel( pScVal->maThumbRect );
            pNew->maButton1Rect = rDev.ImplLogicToDevicePixel( pScVal->maButton1Rect );
            pNew->maButton2Rect = rDev.ImplLogicToDevicePixel( pScVal->maButton2Rect );
        }
        break;
    case CTRL_SPINBUTTONS:
        {
            const SpinbuttonValue* pSpVal = static_cast<const SpinbuttonValue*>(&rVal);
            SpinbuttonValue* pNew = new SpinbuttonValue( *pSpVal );
            aResult.reset( pNew );
            pNew->maUpperRect = rDev.ImplLogicToDevicePixel( pSpVal->maUpperRect );
            pNew->maLowerRect = rDev.ImplLogicToDevicePixel( pSpVal->maLowerRect );
        }
        break;
    case CTRL_TOOLBAR:
        {
            const ToolbarValue* pTVal = static_cast<const ToolbarValue*>(&rVal);
            ToolbarValue* pNew = new ToolbarValue( *pTVal );
            aResult.reset( pNew );
            pNew->maGripRect = rDev.ImplLogicToDevicePixel( pTVal->maGripRect );
        }
        break;
    case CTRL_TAB_ITEM:
        {
            const TabitemValue* pTIVal = static_cast<const TabitemValue*>(&rVal);
            TabitemValue* pNew = new TabitemValue( *pTIVal );
            aResult.reset( pNew );
        }
        break;
    case CTRL_MENUBAR:
        {
            const MenubarValue* pMVal = static_cast<const MenubarValue*>(&rVal);
            MenubarValue* pNew = new MenubarValue( *pMVal );
            aResult.reset( pNew );
        }
        break;
    case CTRL_PUSHBUTTON:
        {
            const PushButtonValue* pBVal = static_cast<const PushButtonValue*>(&rVal);
            PushButtonValue* pNew = new PushButtonValue( *pBVal );
            aResult.reset( pNew );
        }
        break;
    case CTRL_GENERIC:
            aResult.reset( new ImplControlValue( rVal ) );
            break;
    case CTRL_MENU_POPUP:
        {
            const MenupopupValue* pMVal = static_cast<const MenupopupValue*>(&rVal);
            MenupopupValue* pNew = new MenupopupValue( *pMVal );
            pNew->maItemRect = rDev.ImplLogicToDevicePixel( pMVal->maItemRect );
            aResult.reset( pNew );
        }
        break;
    default:
        OSL_FAIL( "unknown ImplControlValue type !" );
        break;
    }
    return aResult;
}
bool OutputDevice::DrawNativeControl( ControlType nType,
                            ControlPart nPart,
                            const Rectangle& rControlRegion,
                            ControlState nState,
                            const ImplControlValue& aValue,
                            const OUString& aCaption )
{
    if( !EnableNativeWidget( *this ) )
        return false;

    // make sure the current clip region is initialized correctly
    if ( !mpGraphics )
        if ( !AcquireGraphics() )
            return false;

    if ( mbInitClipRegion )
        InitClipRegion();
    if ( mbOutputClipped )
        return true;

    if ( mbInitLineColor )
        InitLineColor();
    if ( mbInitFillColor )
        InitFillColor();

    // Convert the coordinates from relative to Window-absolute, so we draw
    // in the correct place in platform code
    boost::shared_ptr< ImplControlValue > aScreenCtrlValue( TransformControlValue( aValue, *this ) );
    Rectangle screenRegion( ImplLogicToDevicePixel( rControlRegion ) );

    Region aTestRegion( GetActiveClipRegion() );
    aTestRegion.Intersect( rControlRegion );
    if (aTestRegion == Region(rControlRegion))
        nState |= CTRL_CACHING_ALLOWED;   // control is not clipped, caching allowed

    bool bRet = mpGraphics->DrawNativeControl(nType, nPart, screenRegion, nState, *aScreenCtrlValue, aCaption, this );

    return bRet;
}

bool OutputDevice::GetNativeControlRegion(  ControlType nType,
                                ControlPart nPart,
                                const Rectangle& rControlRegion,
                                ControlState nState,
                                const ImplControlValue& aValue,
                                const OUString& aCaption,
                                Rectangle &rNativeBoundingRegion,
                                Rectangle &rNativeContentRegion ) const
{
    if( !EnableNativeWidget( *this ) )
        return false;

    if ( !mpGraphics )
        if ( !AcquireGraphics() )
            return false;

    // Convert the coordinates from relative to Window-absolute, so we draw
    // in the correct place in platform code
    boost::shared_ptr< ImplControlValue > aScreenCtrlValue( TransformControlValue( aValue, *this ) );
    Rectangle screenRegion( ImplLogicToDevicePixel( rControlRegion ) );

    bool bRet = mpGraphics->GetNativeControlRegion(nType, nPart, screenRegion, nState, *aScreenCtrlValue,
                                aCaption, rNativeBoundingRegion,
                                rNativeContentRegion, this );
    if( bRet )
    {
        // transform back native regions
        rNativeBoundingRegion = ImplDevicePixelToLogic( rNativeBoundingRegion );
        rNativeContentRegion = ImplDevicePixelToLogic( rNativeContentRegion );
    }

    return bRet;
}

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