<commit_before>#include <stdio.h>
#include <stdexcept>

#include <QMutexLocker>

#include <Utils.hpp>
#include "../firmware/common2015/drivers/cc1201/ti/defines.hpp"
#include "USBRadio.hpp"

// Include this file for base station usb vendor/product ids
#include "../firmware/base2015/usb-interface.hpp"

using namespace std;
using namespace Packet;

// Timeout for control transfers, in milliseconds
static const int Control_Timeout = 1000;

USBRadio::USBRadio() : _mutex(QMutex::Recursive) {
    _sequence = 0;
    _printedError = false;
    _device = nullptr;
    _usb_context = nullptr;
    libusb_init(&_usb_context);

    for (int i = 0; i < NumRXTransfers; ++i) {
        _rxTransfers[i] = libusb_alloc_transfer(0);
    }
}

USBRadio::~USBRadio() {
    if (_device) {
        libusb_close(_device);
    }

    for (int i = 0; i < NumRXTransfers; ++i) {
        libusb_free_transfer(_rxTransfers[i]);
    }

    libusb_exit(_usb_context);
}

bool USBRadio::open() {
    libusb_device** devices = nullptr;
    ssize_t numDevices = libusb_get_device_list(_usb_context, &devices);

    if (numDevices < 0) {
        fprintf(stderr, "libusb_get_device_list failed\n");
        return false;
    }

    int numRadios = 0;
    for (int i = 0; i < numDevices; ++i) {
        struct libusb_device_descriptor desc;
        int err = libusb_get_device_descriptor(devices[i], &desc);
        if (err == 0 && desc.idVendor == RJ_BASE2015_VENDOR_ID &&
            desc.idProduct == RJ_BASE2015_PRODUCT_ID) {
            ++numRadios;
            int err = libusb_open(devices[i], &_device);
            if (err == 0) {
                break;
            }
        }
    }

    libusb_free_device_list(devices, 1);

    if (!numRadios) {
        if (!_printedError) {
            fprintf(stderr, "USBRadio: No radio is connected\n");
            _printedError = true;
        }
        return false;
    }

    if (!_device) {
        if (!_printedError) {
            fprintf(stderr, "USBRadio: All radios are in use\n");
            _printedError = true;
        }
        return false;
    }

    if (libusb_set_configuration(_device, 1)) {
        if (!_printedError) {
            fprintf(stderr, "USBRadio: Can't set configuration\n");
            _printedError = true;
        }
        return false;
    }

    if (libusb_claim_interface(_device, 0)) {
        if (!_printedError) {
            fprintf(stderr, "USBRadio: Can't claim interface\n");
            _printedError = true;
        }
        return false;
    }

    channel(_channel);

    // Start the receive transfers
    for (int i = 0; i < NumRXTransfers; ++i) {
        // Populate the required libusb_transfer fields for a bulk transfer.
        libusb_fill_bulk_transfer(
            _rxTransfers[i],  // the transfer to populate
            _device,  // handle of the device that will handle the transfer
            LIBUSB_ENDPOINT_IN |
                2,  // address of the endpoint where this transfer will be sent
            _rxBuffers[i],          // data buffer
            rtp::Reverse_Size + 2,  // length of data buffer
            rxCompleted,  // callback function to be invoked on transfer
                          // completion
            this,         // user data to pass to callback function
            0);           // timeout for the transfer in milliseconds
        libusb_submit_transfer(_rxTransfers[i]);
    }

    _printedError = false;

    return true;
}

void USBRadio::rxCompleted(libusb_transfer* transfer) {
    USBRadio* radio = (USBRadio*)transfer->user_data;

    if (transfer->status == LIBUSB_TRANSFER_COMPLETED &&
        transfer->actual_length == sizeof(rtp::RobotStatusMessage)) {
        // Parse the packet and add to the list of RadioRx's
        radio->handleRxData(transfer->buffer);
    } else {
        cerr << "bad rx from usbradio" << endl;  // TODO: remove
    }

    // Restart the transfer
    libusb_submit_transfer(transfer);
}

void USBRadio::command(uint8_t cmd) {
    if (libusb_control_transfer(_device,
                                LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR,
                                Base2015ControlCommand::RadioStrobe, 0, cmd,
                                nullptr, 0, Control_Timeout)) {
        throw runtime_error("USBRadio::command control write failed");
    }
}

void USBRadio::write(uint8_t reg, uint8_t value) {
    if (libusb_control_transfer(_device,
                                LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR,
                                Base2015ControlCommand::RadioWriteRegister,
                                value, reg, nullptr, 0, Control_Timeout)) {
        throw runtime_error("USBRadio::write control write failed");
    }
}

uint8_t USBRadio::read(uint8_t reg) {
    uint8_t value = 0;
    if (libusb_control_transfer(_device,
                                LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR,
                                Base2015ControlCommand::RadioReadRegister, 0,
                                reg, &value, 1, Control_Timeout)) {
        throw runtime_error("USBRadio::read control write failed");
    }

    return value;
}

bool USBRadio::isOpen() const { return _device; }

void USBRadio::send(Packet::RadioTx& packet) {
    QMutexLocker lock(&_mutex);
    if (!_device) {
        if (!open()) {
            return;
        }
    }

    uint8_t forward_packet[rtp::Forward_Size];

    // ensure Forward_Size is correct
    static_assert(sizeof(rtp::header_data) + 6 * sizeof(rtp::ControlMessage) ==
                      rtp::Forward_Size,
                  "Forward packet contents exceeds buffer size");

    // Unit conversions
    static const float Seconds_Per_Cycle = 0.005f;
    static const float Meters_Per_Tick = 0.026f * 2 * M_PI / 6480.0f;
    static const float Radians_Per_Tick = 0.026f * M_PI / (0.0812f * 3240.0f);

    rtp::header_data* header = (rtp::header_data*)forward_packet;
    header->port = rtp::Port::CONTROL;
    header->address = rtp::BROADCAST_ADDRESS;
    header->type = rtp::header_data::Type::Control;

    // Build a forward packet
    for (int slot = 0; slot < 6; ++slot) {
        // Calculate the offset into the @forward_packet for this robot's
        // control message and cast it to a ControlMessage pointer for easy
        // access
        size_t offset =
            sizeof(rtp::header_data) + slot * sizeof(rtp::ControlMessage);
        rtp::ControlMessage* msg =
            (rtp::ControlMessage*)(forward_packet + offset);

        if (slot < packet.robots_size()) {
            const Packet::Control& robot = packet.robots(slot).control();

            // TODO: clarify units/resolution
            float bodyVelX = robot.xvelocity() * Seconds_Per_Cycle /
                             Meters_Per_Tick / sqrtf(2);
            float bodyVelY = robot.yvelocity() * Seconds_Per_Cycle /
                             Meters_Per_Tick / sqrtf(2);
            float bodyVelW =
                robot.avelocity() * Seconds_Per_Cycle / Radians_Per_Tick;

            msg->uid = packet.robots(slot).uid();

            msg->bodyX = clamp((int)roundf(bodyVelX), -511, 511);
            msg->bodyY = clamp((int)roundf(bodyVelY), -511, 511);
            msg->bodyW = clamp((int)roundf(bodyVelW), -511, 511);

            msg->dribbler =
                max(0, min(255, static_cast<uint16_t>(robot.dvelocity()) * 2));

            msg->kickStrength = robot.kcstrength();

            msg->shootMode = robot.shootmode();
            msg->triggerMode = robot.triggermode();
            msg->song = robot.song();
        } else {
            // empty slot
            msg->uid = 0;
        }
    }

    _sequence = (_sequence + 1) & 7;

    // TODO(justin): remove this. skip every other packet because the system
    // can't handle 60Hz.  Not sure exactly where the bottleneck is - this
    // definitely needs to be invesitgated.  If this rate-limit is removed and
    // we try to send at 60Hz, we get TX buffer overflows in the base station.
    if (_sequence % 2 == 0) return;

    // Send the forward packet
    int sent = 0;
    int transferRetCode =
        libusb_bulk_transfer(_device, LIBUSB_ENDPOINT_OUT | 2, forward_packet,
                             sizeof(forward_packet), &sent, Control_Timeout);
    if (transferRetCode != LIBUSB_SUCCESS || sent != sizeof(forward_packet)) {
        fprintf(stderr, "USBRadio: Bulk write failed\n");
        if (transferRetCode != LIBUSB_SUCCESS)
            fprintf(stderr, "  Error: '%s'\n",
                    libusb_error_name(transferRetCode));

        libusb_close(_device);
        _device = nullptr;
    }
}

void USBRadio::receive() {
    QMutexLocker lock(&_mutex);

    if (!_device) {
        if (!open()) {
            return;
        }
    }

    // Handle USB events.  This will call callbacks.
    struct timeval tv = {0, 0};
    libusb_handle_events_timeout(_usb_context, &tv);
}

void USBRadio::handleRxData(uint8_t* buf) {
    RJ::Time rx_time = RJ::timestamp();

    // TODO(justin): should the packet be populated before putting into the
    // queue?

    _reversePackets.push_back(RadioRx());
    RadioRx& packet = _reversePackets.back();

    // TODO(justin): check size of buf?
    rtp::RobotStatusMessage* msg = (rtp::RobotStatusMessage*)buf;

    // TODO(justin): add back missing fields

    packet.set_timestamp(rx_time);
    packet.set_robot_id(msg->uid);
    // packet.set_rssi((int8_t)buf[1] / 2.0 - 74);
    packet.set_battery(msg->battVoltage);
// packet.set_kicker_status(buf[3]);

// // Drive motor status
// for (int i = 0; i < 4; ++i) {
//     packet.add_motor_status(MotorStatus((buf[4] >> (i * 2)) & 3));
// }

// Dribbler status
// packet.add_motor_status(MotorStatus(buf[5] & 3));

// Hardware version
// if (buf[5] & (1 << 4)) {
//     packet.set_hardware_version(RJ2008);
// } else {
//     packet.set_hardware_version(RJ2011);
// }

// packet.set_ball_sense_status(BallSenseStatus((buf[5] >> 2) & 3));
// packet.set_kicker_voltage(buf[6]);

#if 0
	// Encoders
	for (int i = 0; i < 4; ++i)
	{
		int high = (buf[10] >> (i * 2)) & 3;
		int16_t value = buf[6 + i] | (high << 8);
		if (high & 2)
		{
			value |= 0xfc00;
		}
		packet.add_encoders(value);
	}
#endif

#if 0
	if (buf[5] & (1 << 5))
	{
		// Quaternion
		int16_t q0 = buf[7] | (buf[8] << 8);
		int16_t q1 = buf[9] | (buf[10] << 8);
		int16_t q2 = buf[11] | (buf[12] << 8);
		int16_t q3 = buf[13] | (buf[14] << 8);
		packet.mutable_quaternion()->set_q0(q0 / 16384.0);
		packet.mutable_quaternion()->set_q1(q1 / 16384.0);
		packet.mutable_quaternion()->set_q2(q2 / 16384.0);
		packet.mutable_quaternion()->set_q3(q3 / 16384.0);
	}
#endif
}

void USBRadio::channel(int n) {
    QMutexLocker lock(&_mutex);

    if (_device) {
        // TODO(justin): fix
        // write(CHANNR, n);
        // throw std::runtime_error("Channel-setting not implemented for
        // cc1201");

        command(CC1201_STROBE_SIDLE);
        command(CC1201_STROBE_SRX);
    }

    Radio::channel(n);
}
<commit_msg>remove old encoder and quaternion packet data handling<commit_after>#include <stdio.h>
#include <stdexcept>

#include <QMutexLocker>

#include <Utils.hpp>
#include "../firmware/common2015/drivers/cc1201/ti/defines.hpp"
#include "USBRadio.hpp"

// Include this file for base station usb vendor/product ids
#include "../firmware/base2015/usb-interface.hpp"

using namespace std;
using namespace Packet;

// Timeout for control transfers, in milliseconds
static const int Control_Timeout = 1000;

USBRadio::USBRadio() : _mutex(QMutex::Recursive) {
    _sequence = 0;
    _printedError = false;
    _device = nullptr;
    _usb_context = nullptr;
    libusb_init(&_usb_context);

    for (int i = 0; i < NumRXTransfers; ++i) {
        _rxTransfers[i] = libusb_alloc_transfer(0);
    }
}

USBRadio::~USBRadio() {
    if (_device) {
        libusb_close(_device);
    }

    for (int i = 0; i < NumRXTransfers; ++i) {
        libusb_free_transfer(_rxTransfers[i]);
    }

    libusb_exit(_usb_context);
}

bool USBRadio::open() {
    libusb_device** devices = nullptr;
    ssize_t numDevices = libusb_get_device_list(_usb_context, &devices);

    if (numDevices < 0) {
        fprintf(stderr, "libusb_get_device_list failed\n");
        return false;
    }

    int numRadios = 0;
    for (int i = 0; i < numDevices; ++i) {
        struct libusb_device_descriptor desc;
        int err = libusb_get_device_descriptor(devices[i], &desc);
        if (err == 0 && desc.idVendor == RJ_BASE2015_VENDOR_ID &&
            desc.idProduct == RJ_BASE2015_PRODUCT_ID) {
            ++numRadios;
            int err = libusb_open(devices[i], &_device);
            if (err == 0) {
                break;
            }
        }
    }

    libusb_free_device_list(devices, 1);

    if (!numRadios) {
        if (!_printedError) {
            fprintf(stderr, "USBRadio: No radio is connected\n");
            _printedError = true;
        }
        return false;
    }

    if (!_device) {
        if (!_printedError) {
            fprintf(stderr, "USBRadio: All radios are in use\n");
            _printedError = true;
        }
        return false;
    }

    if (libusb_set_configuration(_device, 1)) {
        if (!_printedError) {
            fprintf(stderr, "USBRadio: Can't set configuration\n");
            _printedError = true;
        }
        return false;
    }

    if (libusb_claim_interface(_device, 0)) {
        if (!_printedError) {
            fprintf(stderr, "USBRadio: Can't claim interface\n");
            _printedError = true;
        }
        return false;
    }

    channel(_channel);

    // Start the receive transfers
    for (int i = 0; i < NumRXTransfers; ++i) {
        // Populate the required libusb_transfer fields for a bulk transfer.
        libusb_fill_bulk_transfer(
            _rxTransfers[i],  // the transfer to populate
            _device,  // handle of the device that will handle the transfer
            LIBUSB_ENDPOINT_IN |
                2,  // address of the endpoint where this transfer will be sent
            _rxBuffers[i],          // data buffer
            rtp::Reverse_Size + 2,  // length of data buffer
            rxCompleted,  // callback function to be invoked on transfer
                          // completion
            this,         // user data to pass to callback function
            0);           // timeout for the transfer in milliseconds
        libusb_submit_transfer(_rxTransfers[i]);
    }

    _printedError = false;

    return true;
}

void USBRadio::rxCompleted(libusb_transfer* transfer) {
    USBRadio* radio = (USBRadio*)transfer->user_data;

    if (transfer->status == LIBUSB_TRANSFER_COMPLETED &&
        transfer->actual_length == sizeof(rtp::RobotStatusMessage)) {
        // Parse the packet and add to the list of RadioRx's
        radio->handleRxData(transfer->buffer);
    } else {
        cerr << "bad rx from usbradio" << endl;  // TODO: remove
    }

    // Restart the transfer
    libusb_submit_transfer(transfer);
}

void USBRadio::command(uint8_t cmd) {
    if (libusb_control_transfer(_device,
                                LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR,
                                Base2015ControlCommand::RadioStrobe, 0, cmd,
                                nullptr, 0, Control_Timeout)) {
        throw runtime_error("USBRadio::command control write failed");
    }
}

void USBRadio::write(uint8_t reg, uint8_t value) {
    if (libusb_control_transfer(_device,
                                LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR,
                                Base2015ControlCommand::RadioWriteRegister,
                                value, reg, nullptr, 0, Control_Timeout)) {
        throw runtime_error("USBRadio::write control write failed");
    }
}

uint8_t USBRadio::read(uint8_t reg) {
    uint8_t value = 0;
    if (libusb_control_transfer(_device,
                                LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR,
                                Base2015ControlCommand::RadioReadRegister, 0,
                                reg, &value, 1, Control_Timeout)) {
        throw runtime_error("USBRadio::read control write failed");
    }

    return value;
}

bool USBRadio::isOpen() const { return _device; }

void USBRadio::send(Packet::RadioTx& packet) {
    QMutexLocker lock(&_mutex);
    if (!_device) {
        if (!open()) {
            return;
        }
    }

    uint8_t forward_packet[rtp::Forward_Size];

    // ensure Forward_Size is correct
    static_assert(sizeof(rtp::header_data) + 6 * sizeof(rtp::ControlMessage) ==
                      rtp::Forward_Size,
                  "Forward packet contents exceeds buffer size");

    // Unit conversions
    static const float Seconds_Per_Cycle = 0.005f;
    static const float Meters_Per_Tick = 0.026f * 2 * M_PI / 6480.0f;
    static const float Radians_Per_Tick = 0.026f * M_PI / (0.0812f * 3240.0f);

    rtp::header_data* header = (rtp::header_data*)forward_packet;
    header->port = rtp::Port::CONTROL;
    header->address = rtp::BROADCAST_ADDRESS;
    header->type = rtp::header_data::Type::Control;

    // Build a forward packet
    for (int slot = 0; slot < 6; ++slot) {
        // Calculate the offset into the @forward_packet for this robot's
        // control message and cast it to a ControlMessage pointer for easy
        // access
        size_t offset =
            sizeof(rtp::header_data) + slot * sizeof(rtp::ControlMessage);
        rtp::ControlMessage* msg =
            (rtp::ControlMessage*)(forward_packet + offset);

        if (slot < packet.robots_size()) {
            const Packet::Control& robot = packet.robots(slot).control();

            // TODO: clarify units/resolution
            float bodyVelX = robot.xvelocity() * Seconds_Per_Cycle /
                             Meters_Per_Tick / sqrtf(2);
            float bodyVelY = robot.yvelocity() * Seconds_Per_Cycle /
                             Meters_Per_Tick / sqrtf(2);
            float bodyVelW =
                robot.avelocity() * Seconds_Per_Cycle / Radians_Per_Tick;

            msg->uid = packet.robots(slot).uid();

            msg->bodyX = clamp((int)roundf(bodyVelX), -511, 511);
            msg->bodyY = clamp((int)roundf(bodyVelY), -511, 511);
            msg->bodyW = clamp((int)roundf(bodyVelW), -511, 511);

            msg->dribbler =
                max(0, min(255, static_cast<uint16_t>(robot.dvelocity()) * 2));

            msg->kickStrength = robot.kcstrength();

            msg->shootMode = robot.shootmode();
            msg->triggerMode = robot.triggermode();
            msg->song = robot.song();
        } else {
            // empty slot
            msg->uid = 0;
        }
    }

    _sequence = (_sequence + 1) & 7;

    // TODO(justin): remove this. skip every other packet because the system
    // can't handle 60Hz.  Not sure exactly where the bottleneck is - this
    // definitely needs to be invesitgated.  If this rate-limit is removed and
    // we try to send at 60Hz, we get TX buffer overflows in the base station.
    if (_sequence % 2 == 0) return;

    // Send the forward packet
    int sent = 0;
    int transferRetCode =
        libusb_bulk_transfer(_device, LIBUSB_ENDPOINT_OUT | 2, forward_packet,
                             sizeof(forward_packet), &sent, Control_Timeout);
    if (transferRetCode != LIBUSB_SUCCESS || sent != sizeof(forward_packet)) {
        fprintf(stderr, "USBRadio: Bulk write failed\n");
        if (transferRetCode != LIBUSB_SUCCESS)
            fprintf(stderr, "  Error: '%s'\n",
                    libusb_error_name(transferRetCode));

        libusb_close(_device);
        _device = nullptr;
    }
}

void USBRadio::receive() {
    QMutexLocker lock(&_mutex);

    if (!_device) {
        if (!open()) {
            return;
        }
    }

    // Handle USB events.  This will call callbacks.
    struct timeval tv = {0, 0};
    libusb_handle_events_timeout(_usb_context, &tv);
}

void USBRadio::handleRxData(uint8_t* buf) {
    RJ::Time rx_time = RJ::timestamp();

    // TODO(justin): should the packet be populated before putting into the
    // queue?

    _reversePackets.push_back(RadioRx());
    RadioRx& packet = _reversePackets.back();

    // TODO(justin): check size of buf?
    rtp::RobotStatusMessage* msg = (rtp::RobotStatusMessage*)buf;

    // TODO(justin): add back missing fields

    packet.set_timestamp(rx_time);
    packet.set_robot_id(msg->uid);
    // packet.set_rssi((int8_t)buf[1] / 2.0 - 74);
    packet.set_battery(msg->battVoltage);
// packet.set_kicker_status(buf[3]);

// // Drive motor status
// for (int i = 0; i < 4; ++i) {
//     packet.add_motor_status(MotorStatus((buf[4] >> (i * 2)) & 3));
// }

// Dribbler status
// packet.add_motor_status(MotorStatus(buf[5] & 3));

// Hardware version
// if (buf[5] & (1 << 4)) {
//     packet.set_hardware_version(RJ2008);
// } else {
//     packet.set_hardware_version(RJ2011);
// }

// packet.set_ball_sense_status(BallSenseStatus((buf[5] >> 2) & 3));
// packet.set_kicker_voltage(buf[6]);
}

void USBRadio::channel(int n) {
    QMutexLocker lock(&_mutex);

    if (_device) {
        // TODO(justin): fix
        // write(CHANNR, n);
        // throw std::runtime_error("Channel-setting not implemented for
        // cc1201");

        command(CC1201_STROBE_SIDLE);
        command(CC1201_STROBE_SRX);
    }

    Radio::channel(n);
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2013-2016 Rapptz and contributors

// 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.

#ifndef SOL_DEFAULT_CONSTRUCTOR_HPP
#define SOL_DEFAULT_CONSTRUCTOR_HPP

#include <memory>
#include "traits.hpp"

namespace sol {
struct default_construct {
    template<typename T, typename... Args>
    void operator()(T&& obj, Args&&... args) const {
        std::allocator<Unqualified<T>> alloc{};
        alloc.construct(obj, std::forward<Args>(args)...);
    }
};

template <typename T>
struct placement_construct {
    T obj;

    template <typename... Args>
    placement_construct( Args&&... args ) : obj(std::forward<Args>(args)...) {

    }

    template<typename... Args>
    void operator()(Args&&... args) const {
        std::allocator<Unqualified<T>> alloc{};
        alloc.construct(obj, std::forward<Args>(args)...);
    }
};

} // sol

#endif // SOL_DEFAULT_CONSTRUCTOR_HPP
<commit_msg>Git had a sneeze and couldn't properly remove this file...<commit_after><|endoftext|>


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

#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"

const std::wstring DevToolsWindow::kDevToolsApp = L"DevToolsApp";

// static
TabContents* DevToolsWindow::GetDevToolsContents(TabContents* inspected_tab) {
  if (!inspected_tab) {
    return NULL;
  }

  if (!DevToolsManager::GetInstance())
    return NULL;  // Happens only in tests.

  DevToolsClientHost* client_host = DevToolsManager::GetInstance()->
          GetDevToolsClientHostFor(inspected_tab->render_view_host());
  if (!client_host) {
    return NULL;
  }

  DevToolsWindow* window = client_host->AsDevToolsWindow();
  if (!window || !window->is_docked()) {
    return NULL;
  }
  return window->tab_contents();
}

DevToolsWindow::DevToolsWindow(Profile* profile,
                               RenderViewHost* inspected_rvh,
                               bool docked)
    : profile_(profile),
      browser_(NULL),
      docked_(docked),
      is_loaded_(false),
      action_on_load_(DEVTOOLS_TOGGLE_ACTION_NONE) {
  // Create TabContents with devtools.
  tab_contents_ = new TabContents(profile, NULL, MSG_ROUTING_NONE, NULL);
  tab_contents_->render_view_host()->AllowBindings(BindingsPolicy::DOM_UI);
  tab_contents_->controller().LoadURL(
      GetDevToolsUrl(), GURL(), PageTransition::START_PAGE);

  // Wipe out page icon so that the default application icon is used.
  NavigationEntry* entry = tab_contents_->controller().GetActiveEntry();
  entry->favicon().set_bitmap(SkBitmap());
  entry->favicon().set_is_valid(true);

  // Register on-load actions.
  registrar_.Add(this,
                 NotificationType::LOAD_STOP,
                 Source<NavigationController>(&tab_contents_->controller()));
  registrar_.Add(this,
                 NotificationType::TAB_CLOSING,
                 Source<NavigationController>(&tab_contents_->controller()));
  registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
                 NotificationService::AllSources());
  inspected_tab_ = inspected_rvh->delegate()->GetAsTabContents();
}

DevToolsWindow::~DevToolsWindow() {
}

DevToolsWindow* DevToolsWindow::AsDevToolsWindow() {
  return this;
}

void DevToolsWindow::SendMessageToClient(const IPC::Message& message) {
  RenderViewHost* target_host = tab_contents_->render_view_host();
  IPC::Message* m =  new IPC::Message(message);
  m->set_routing_id(target_host->routing_id());
  target_host->Send(m);
}

void DevToolsWindow::InspectedTabClosing() {
  if (docked_) {
    // Update dev tools to reflect removed dev tools window.

    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->UpdateDevTools();
    // In case of docked tab_contents we own it, so delete here.
    delete tab_contents_;

    delete this;
  } else {
    // First, initiate self-destruct to free all the registrars.
    // Then close all tabs. Browser will take care of deleting tab_contents
    // for us.
    Browser* browser = browser_;
    delete this;
    browser->CloseAllTabs();
  }
}

void DevToolsWindow::Show(DevToolsToggleAction action) {
  if (docked_) {
    // Just tell inspected browser to update splitter.
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window) {
      tab_contents_->set_delegate(this);
      inspected_window->UpdateDevTools();
      SetAttachedWindow();
      tab_contents_->view()->SetInitialFocus();
      ScheduleAction(action);
      return;
    } else {
      // Sometimes we don't know where to dock. Stay undocked.
      docked_ = false;
    }
  }

  if (!browser_)
    CreateDevToolsBrowser();

  // Avoid consecutive window switching if the devtools window has been opened
  // and the Inspect Element shortcut is pressed in the inspected tab.
  bool should_show_window =
      !browser_ || action != DEVTOOLS_TOGGLE_ACTION_INSPECT;
  if (should_show_window)
    browser_->window()->Show();
  SetAttachedWindow();
  if (should_show_window)
    tab_contents_->view()->SetInitialFocus();

  ScheduleAction(action);
}

void DevToolsWindow::Activate() {
  if (!docked_) {
    if (!browser_->window()->IsActive()) {
      browser_->window()->Activate();
    }
  } else {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      tab_contents_->view()->Focus();
  }
}

void DevToolsWindow::SetDocked(bool docked) {
  if (docked_ == docked)
    return;
  if (docked && !GetInspectedBrowserWindow()) {
    // Cannot dock, avoid window flashing due to close-reopen cycle.
    return;
  }
  docked_ = docked;

  if (docked) {
    // Detach window from the external devtools browser. It will lead to
    // the browser object's close and delete. Remove observer first.
    TabStripModel* tabstrip_model = browser_->tabstrip_model();
    tabstrip_model->DetachTabContentsAt(
        tabstrip_model->GetIndexOfTabContents(tab_contents_));
    browser_ = NULL;
  } else {
    // Update inspected window to hide split and reset it.
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window) {
      inspected_window->UpdateDevTools();
      inspected_window = NULL;
    }
  }
  Show(DEVTOOLS_TOGGLE_ACTION_NONE);
}

RenderViewHost* DevToolsWindow::GetRenderViewHost() {
  return tab_contents_->render_view_host();
}

void DevToolsWindow::CreateDevToolsBrowser() {
  // TODO(pfeldman): Make browser's getter for this key static.
  std::wstring wp_key = L"";
  wp_key.append(prefs::kBrowserWindowPlacement);
  wp_key.append(L"_");
  wp_key.append(kDevToolsApp);

  PrefService* prefs = g_browser_process->local_state();
  if (!prefs->FindPreference(wp_key.c_str())) {
    prefs->RegisterDictionaryPref(wp_key.c_str());
  }

  const DictionaryValue* wp_pref = prefs->GetDictionary(wp_key.c_str());
  if (!wp_pref) {
    DictionaryValue* defaults = prefs->GetMutableDictionary(wp_key.c_str());
    defaults->SetInteger(L"left", 100);
    defaults->SetInteger(L"top", 100);
    defaults->SetInteger(L"right", 740);
    defaults->SetInteger(L"bottom", 740);
    defaults->SetBoolean(L"maximized", false);
    defaults->SetBoolean(L"always_on_top", false);
  }

  browser_ = Browser::CreateForDevTools(profile_);
  browser_->tabstrip_model()->AddTabContents(
      tab_contents_, -1, PageTransition::START_PAGE,
      TabStripModel::ADD_SELECTED);
}

BrowserWindow* DevToolsWindow::GetInspectedBrowserWindow() {
  for (BrowserList::const_iterator it = BrowserList::begin();
       it != BrowserList::end(); ++it) {
    Browser* browser = *it;
    for (int i = 0; i < browser->tab_count(); ++i) {
      TabContents* tab_contents = browser->GetTabContentsAt(i);
      if (tab_contents == inspected_tab_) {
        return browser->window();
      }
    }
  }
  return NULL;
}

void DevToolsWindow::SetAttachedWindow() {
  tab_contents_->render_view_host()->
      ExecuteJavascriptInWebFrame(
          L"", docked_ ? L"WebInspector.setAttachedWindow(true);" :
                         L"WebInspector.setAttachedWindow(false);");
}

void DevToolsWindow::Observe(NotificationType type,
                             const NotificationSource& source,
                             const NotificationDetails& details) {
  if (type == NotificationType::LOAD_STOP) {
    SetAttachedWindow();
    is_loaded_ = true;
    UpdateTheme();
    DoAction();
  } else if (type == NotificationType::TAB_CLOSING) {
    if (Source<NavigationController>(source).ptr() ==
            &tab_contents_->controller()) {
      // This happens when browser closes all of its tabs as a result
      // of window.Close event.
      // Notify manager that this DevToolsClientHost no longer exists and
      // initiate self-destuct here.
      NotifyCloseListener();
      delete this;
    }
  } else if (type == NotificationType::BROWSER_THEME_CHANGED) {
    UpdateTheme();
  }
}

void DevToolsWindow::ScheduleAction(DevToolsToggleAction action) {
  action_on_load_ = action;
  if (is_loaded_)
    DoAction();
}

void DevToolsWindow::DoAction() {
  // TODO: these messages should be pushed through the WebKit API instead.
  switch (action_on_load_) {
    case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE:
      tab_contents_->render_view_host()->
          ExecuteJavascriptInWebFrame(L"", L"WebInspector.showConsole();");
      break;
    case DEVTOOLS_TOGGLE_ACTION_INSPECT:
      tab_contents_->render_view_host()->
          ExecuteJavascriptInWebFrame(
              L"", L"WebInspector.toggleSearchingForNode();");
    case DEVTOOLS_TOGGLE_ACTION_NONE:
      // Do nothing.
      break;
    default:
      NOTREACHED();
  }
  action_on_load_ = DEVTOOLS_TOGGLE_ACTION_NONE;
}

std::string SkColorToRGBAString(SkColor color) {
  // We convert the alpha using DoubleToString because StringPrintf will use
  // locale specific formatters (e.g., use , instead of . in German).
  return StringPrintf("rgba(%d,%d,%d,%s)", SkColorGetR(color),
      SkColorGetG(color), SkColorGetB(color),
      DoubleToString(SkColorGetA(color) / 255.0).c_str());
}

GURL DevToolsWindow::GetDevToolsUrl() {
  BrowserThemeProvider* tp = profile_->GetThemeProvider();
  CHECK(tp);

  SkColor color_toolbar =
      tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
  SkColor color_tab_text =
      tp->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT);

  std::string url_string = StringPrintf(
      "%sdevtools.html?docked=%s&toolbar_color=%s&text_color=%s",
      chrome::kChromeUIDevToolsURL,
      docked_ ? "true" : "false",
      SkColorToRGBAString(color_toolbar).c_str(),
      SkColorToRGBAString(color_tab_text).c_str());
  return GURL(url_string);
}

void DevToolsWindow::UpdateTheme() {
  BrowserThemeProvider* tp = profile_->GetThemeProvider();
  CHECK(tp);

  SkColor color_toolbar =
      tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
  SkColor color_tab_text =
      tp->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
  std::string command = StringPrintf(
      "WebInspector.setToolbarColors(\"%s\", \"%s\")",
      SkColorToRGBAString(color_toolbar).c_str(),
      SkColorToRGBAString(color_tab_text).c_str());
  tab_contents_->render_view_host()->
      ExecuteJavascriptInWebFrame(L"", UTF8ToWide(command));
}

bool DevToolsWindow::PreHandleKeyboardEvent(
    const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
  if (docked_) {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      return inspected_window->PreHandleKeyboardEvent(
          event, is_keyboard_shortcut);
  }
  return false;
}

void DevToolsWindow::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
  if (docked_) {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->HandleKeyboardEvent(event);
  }
}
<commit_msg>Show DevTools window when the Inspect shortcut is hit for the first time<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"

const std::wstring DevToolsWindow::kDevToolsApp = L"DevToolsApp";

// static
TabContents* DevToolsWindow::GetDevToolsContents(TabContents* inspected_tab) {
  if (!inspected_tab) {
    return NULL;
  }

  if (!DevToolsManager::GetInstance())
    return NULL;  // Happens only in tests.

  DevToolsClientHost* client_host = DevToolsManager::GetInstance()->
          GetDevToolsClientHostFor(inspected_tab->render_view_host());
  if (!client_host) {
    return NULL;
  }

  DevToolsWindow* window = client_host->AsDevToolsWindow();
  if (!window || !window->is_docked()) {
    return NULL;
  }
  return window->tab_contents();
}

DevToolsWindow::DevToolsWindow(Profile* profile,
                               RenderViewHost* inspected_rvh,
                               bool docked)
    : profile_(profile),
      browser_(NULL),
      docked_(docked),
      is_loaded_(false),
      action_on_load_(DEVTOOLS_TOGGLE_ACTION_NONE) {
  // Create TabContents with devtools.
  tab_contents_ = new TabContents(profile, NULL, MSG_ROUTING_NONE, NULL);
  tab_contents_->render_view_host()->AllowBindings(BindingsPolicy::DOM_UI);
  tab_contents_->controller().LoadURL(
      GetDevToolsUrl(), GURL(), PageTransition::START_PAGE);

  // Wipe out page icon so that the default application icon is used.
  NavigationEntry* entry = tab_contents_->controller().GetActiveEntry();
  entry->favicon().set_bitmap(SkBitmap());
  entry->favicon().set_is_valid(true);

  // Register on-load actions.
  registrar_.Add(this,
                 NotificationType::LOAD_STOP,
                 Source<NavigationController>(&tab_contents_->controller()));
  registrar_.Add(this,
                 NotificationType::TAB_CLOSING,
                 Source<NavigationController>(&tab_contents_->controller()));
  registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
                 NotificationService::AllSources());
  inspected_tab_ = inspected_rvh->delegate()->GetAsTabContents();
}

DevToolsWindow::~DevToolsWindow() {
}

DevToolsWindow* DevToolsWindow::AsDevToolsWindow() {
  return this;
}

void DevToolsWindow::SendMessageToClient(const IPC::Message& message) {
  RenderViewHost* target_host = tab_contents_->render_view_host();
  IPC::Message* m =  new IPC::Message(message);
  m->set_routing_id(target_host->routing_id());
  target_host->Send(m);
}

void DevToolsWindow::InspectedTabClosing() {
  if (docked_) {
    // Update dev tools to reflect removed dev tools window.

    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->UpdateDevTools();
    // In case of docked tab_contents we own it, so delete here.
    delete tab_contents_;

    delete this;
  } else {
    // First, initiate self-destruct to free all the registrars.
    // Then close all tabs. Browser will take care of deleting tab_contents
    // for us.
    Browser* browser = browser_;
    delete this;
    browser->CloseAllTabs();
  }
}

void DevToolsWindow::Show(DevToolsToggleAction action) {
  if (docked_) {
    // Just tell inspected browser to update splitter.
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window) {
      tab_contents_->set_delegate(this);
      inspected_window->UpdateDevTools();
      SetAttachedWindow();
      tab_contents_->view()->SetInitialFocus();
      ScheduleAction(action);
      return;
    } else {
      // Sometimes we don't know where to dock. Stay undocked.
      docked_ = false;
    }
  }

  // Avoid consecutive window switching if the devtools window has been opened
  // and the Inspect Element shortcut is pressed in the inspected tab.
  bool should_show_window =
      !browser_ || action != DEVTOOLS_TOGGLE_ACTION_INSPECT;

  if (!browser_)
    CreateDevToolsBrowser();

  if (should_show_window)
    browser_->window()->Show();
  SetAttachedWindow();
  if (should_show_window)
    tab_contents_->view()->SetInitialFocus();

  ScheduleAction(action);
}

void DevToolsWindow::Activate() {
  if (!docked_) {
    if (!browser_->window()->IsActive()) {
      browser_->window()->Activate();
    }
  } else {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      tab_contents_->view()->Focus();
  }
}

void DevToolsWindow::SetDocked(bool docked) {
  if (docked_ == docked)
    return;
  if (docked && !GetInspectedBrowserWindow()) {
    // Cannot dock, avoid window flashing due to close-reopen cycle.
    return;
  }
  docked_ = docked;

  if (docked) {
    // Detach window from the external devtools browser. It will lead to
    // the browser object's close and delete. Remove observer first.
    TabStripModel* tabstrip_model = browser_->tabstrip_model();
    tabstrip_model->DetachTabContentsAt(
        tabstrip_model->GetIndexOfTabContents(tab_contents_));
    browser_ = NULL;
  } else {
    // Update inspected window to hide split and reset it.
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window) {
      inspected_window->UpdateDevTools();
      inspected_window = NULL;
    }
  }
  Show(DEVTOOLS_TOGGLE_ACTION_NONE);
}

RenderViewHost* DevToolsWindow::GetRenderViewHost() {
  return tab_contents_->render_view_host();
}

void DevToolsWindow::CreateDevToolsBrowser() {
  // TODO(pfeldman): Make browser's getter for this key static.
  std::wstring wp_key = L"";
  wp_key.append(prefs::kBrowserWindowPlacement);
  wp_key.append(L"_");
  wp_key.append(kDevToolsApp);

  PrefService* prefs = g_browser_process->local_state();
  if (!prefs->FindPreference(wp_key.c_str())) {
    prefs->RegisterDictionaryPref(wp_key.c_str());
  }

  const DictionaryValue* wp_pref = prefs->GetDictionary(wp_key.c_str());
  if (!wp_pref) {
    DictionaryValue* defaults = prefs->GetMutableDictionary(wp_key.c_str());
    defaults->SetInteger(L"left", 100);
    defaults->SetInteger(L"top", 100);
    defaults->SetInteger(L"right", 740);
    defaults->SetInteger(L"bottom", 740);
    defaults->SetBoolean(L"maximized", false);
    defaults->SetBoolean(L"always_on_top", false);
  }

  browser_ = Browser::CreateForDevTools(profile_);
  browser_->tabstrip_model()->AddTabContents(
      tab_contents_, -1, PageTransition::START_PAGE,
      TabStripModel::ADD_SELECTED);
}

BrowserWindow* DevToolsWindow::GetInspectedBrowserWindow() {
  for (BrowserList::const_iterator it = BrowserList::begin();
       it != BrowserList::end(); ++it) {
    Browser* browser = *it;
    for (int i = 0; i < browser->tab_count(); ++i) {
      TabContents* tab_contents = browser->GetTabContentsAt(i);
      if (tab_contents == inspected_tab_) {
        return browser->window();
      }
    }
  }
  return NULL;
}

void DevToolsWindow::SetAttachedWindow() {
  tab_contents_->render_view_host()->
      ExecuteJavascriptInWebFrame(
          L"", docked_ ? L"WebInspector.setAttachedWindow(true);" :
                         L"WebInspector.setAttachedWindow(false);");
}

void DevToolsWindow::Observe(NotificationType type,
                             const NotificationSource& source,
                             const NotificationDetails& details) {
  if (type == NotificationType::LOAD_STOP) {
    SetAttachedWindow();
    is_loaded_ = true;
    UpdateTheme();
    DoAction();
  } else if (type == NotificationType::TAB_CLOSING) {
    if (Source<NavigationController>(source).ptr() ==
            &tab_contents_->controller()) {
      // This happens when browser closes all of its tabs as a result
      // of window.Close event.
      // Notify manager that this DevToolsClientHost no longer exists and
      // initiate self-destuct here.
      NotifyCloseListener();
      delete this;
    }
  } else if (type == NotificationType::BROWSER_THEME_CHANGED) {
    UpdateTheme();
  }
}

void DevToolsWindow::ScheduleAction(DevToolsToggleAction action) {
  action_on_load_ = action;
  if (is_loaded_)
    DoAction();
}

void DevToolsWindow::DoAction() {
  // TODO: these messages should be pushed through the WebKit API instead.
  switch (action_on_load_) {
    case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE:
      tab_contents_->render_view_host()->
          ExecuteJavascriptInWebFrame(L"", L"WebInspector.showConsole();");
      break;
    case DEVTOOLS_TOGGLE_ACTION_INSPECT:
      tab_contents_->render_view_host()->
          ExecuteJavascriptInWebFrame(
              L"", L"WebInspector.toggleSearchingForNode();");
    case DEVTOOLS_TOGGLE_ACTION_NONE:
      // Do nothing.
      break;
    default:
      NOTREACHED();
  }
  action_on_load_ = DEVTOOLS_TOGGLE_ACTION_NONE;
}

std::string SkColorToRGBAString(SkColor color) {
  // We convert the alpha using DoubleToString because StringPrintf will use
  // locale specific formatters (e.g., use , instead of . in German).
  return StringPrintf("rgba(%d,%d,%d,%s)", SkColorGetR(color),
      SkColorGetG(color), SkColorGetB(color),
      DoubleToString(SkColorGetA(color) / 255.0).c_str());
}

GURL DevToolsWindow::GetDevToolsUrl() {
  BrowserThemeProvider* tp = profile_->GetThemeProvider();
  CHECK(tp);

  SkColor color_toolbar =
      tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
  SkColor color_tab_text =
      tp->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT);

  std::string url_string = StringPrintf(
      "%sdevtools.html?docked=%s&toolbar_color=%s&text_color=%s",
      chrome::kChromeUIDevToolsURL,
      docked_ ? "true" : "false",
      SkColorToRGBAString(color_toolbar).c_str(),
      SkColorToRGBAString(color_tab_text).c_str());
  return GURL(url_string);
}

void DevToolsWindow::UpdateTheme() {
  BrowserThemeProvider* tp = profile_->GetThemeProvider();
  CHECK(tp);

  SkColor color_toolbar =
      tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
  SkColor color_tab_text =
      tp->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
  std::string command = StringPrintf(
      "WebInspector.setToolbarColors(\"%s\", \"%s\")",
      SkColorToRGBAString(color_toolbar).c_str(),
      SkColorToRGBAString(color_tab_text).c_str());
  tab_contents_->render_view_host()->
      ExecuteJavascriptInWebFrame(L"", UTF8ToWide(command));
}

bool DevToolsWindow::PreHandleKeyboardEvent(
    const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
  if (docked_) {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      return inspected_window->PreHandleKeyboardEvent(
          event, is_keyboard_shortcut);
  }
  return false;
}

void DevToolsWindow::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
  if (docked_) {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->HandleKeyboardEvent(event);
  }
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>
#include <sstream>

#include <cmath>

#include "filtrations/Data.hh"

#include "geometry/RipsExpander.hh"

#include "persistentHomology/ConnectedComponents.hh"

#include "topology/CliqueGraph.hh"
#include "topology/Simplex.hh"
#include "topology/SimplicialComplex.hh"

#include "topology/io/EdgeLists.hh"
#include "topology/io/GML.hh"

#include "utilities/Filesystem.hh"

using DataType           = double;
using VertexType         = unsigned;
using Simplex            = aleph::topology::Simplex<DataType, VertexType>;
using SimplicialComplex  = aleph::topology::SimplicialComplex<Simplex>;
using PersistenceDiagram = aleph::PersistenceDiagram<DataType>;

std::string formatOutput( const std::string& prefix, unsigned k, unsigned K )
{
  std::ostringstream stream;
  stream << prefix;
  stream << std::setw( int( std::log10( K ) + 1 ) ) << std::setfill( '0' ) << k;
  stream << ".txt";

  return stream.str();
}

void usage()
{
  std::cerr << "Usage: clique-persistence-diagram FILE K\n"
            << "\n"
            << "Calculates the clique persistence diagram for FILE, which is\n"
            << "supposed to be a weighted graph. The K parameter denotes the\n"
            << "maximum dimension of a simplex for extracting a clique graph\n"
            << "and tracking persistence of clique communities.\n\n";
}

int main( int argc, char** argv )
{
  if( argc <= 2 )
  {
    usage();
    return -1;
  }

  std::string filename = argv[1];
  unsigned maxK        = static_cast<unsigned>( std::stoul( argv[2] ) );

  SimplicialComplex K;

  // Input -------------------------------------------------------------

  std::cerr << "* Reading '" << filename << "'...";

  if( aleph::utilities::extension( filename ) == ".gml" )
  {
    aleph::topology::io::GMLReader reader;
    reader( filename, K );
  }
  else
  {
    aleph::io::EdgeListReader reader;
    reader.setReadWeights( true );
    reader.setTrimLines( true );

    reader( filename, K );
  }

  std::cerr << "finished\n";

  DataType maxWeight = std::numeric_limits<DataType>::lowest();
  for( auto&& simplex : K )
    maxWeight = std::max( maxWeight, simplex.data() );

  // Expansion ---------------------------------------------------------

  aleph::geometry::RipsExpander<SimplicialComplex> ripsExpander;
  K = ripsExpander( K, maxK );
  K = ripsExpander.assignMaximumWeight( K );

  K.sort( aleph::filtrations::Data<Simplex>() );

  for( unsigned k = 1; k <= maxK; k++ )
  {
    std::cerr << "* Extracting " << k << "-cliques graph...";

    auto C
        = aleph::topology::getCliqueGraph( K, k );

    C.sort( aleph::filtrations::Data<Simplex>() );

    std::cerr << "finished\n";

    std::cerr << "* " << k << "-cliques graph has " << C.size() << " simplices\n";

    if( C.empty() )
    {
      std::cerr << "* Stopping here because no further cliques for processing exist\n";
      break;
    }

    auto pd
        = aleph::calculateZeroDimensionalPersistenceDiagram( C );

    {
      using namespace aleph::utilities;
      auto outputFilename = formatOutput( "/tmp/" + stem( basename( filename ) ) + "_k", k, maxK );

      std::cerr << "* Storing output in '" << outputFilename << "'...\n";

      pd.removeDiagonal();

      std::transform( pd.begin(), pd.end(), pd.begin(),
                      [&maxWeight] ( const PersistenceDiagram::Point& p )
                      {
                        if( !std::isfinite( p.y() ) )
                          return PersistenceDiagram::Point( p.x(), maxWeight );
                        else
                          return p;
                      } );

      std::ofstream out( outputFilename );
      out << "# Original filename: " << filename << "\n";
      out << "# k                : " << k        << "\n";
      out << pd << "\n";
    }
  }
}
<commit_msg>Prepared calculation of clique-based centrality measure<commit_after>#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>
#include <sstream>

#include <cmath>

#include "filtrations/Data.hh"

#include "geometry/RipsExpander.hh"

#include "persistentHomology/ConnectedComponents.hh"

#include "topology/CliqueGraph.hh"
#include "topology/Simplex.hh"
#include "topology/SimplicialComplex.hh"

#include "topology/io/EdgeLists.hh"
#include "topology/io/GML.hh"

#include "utilities/Filesystem.hh"

using DataType           = double;
using VertexType         = unsigned;
using Simplex            = aleph::topology::Simplex<DataType, VertexType>;
using SimplicialComplex  = aleph::topology::SimplicialComplex<Simplex>;
using PersistenceDiagram = aleph::PersistenceDiagram<DataType>;

SimplicialComplex filterSimplicialComplex( const SimplicialComplex& K, DataType threshold )
{
  std::vector<Simplex> simplices;

  std::copy_if( K.begin(), K.end(), std::back_inserter( simplices ),
                [&threshold] ( const Simplex& s )
                {
                  // TODO: Less than or equal vs. less than?
                  return s.data() <= threshold;
                } );

  return SimplicialComplex( simplices.begin(), simplices.end() );
}

std::string formatOutput( const std::string& prefix, unsigned k, unsigned K )
{
  std::ostringstream stream;
  stream << prefix;
  stream << std::setw( int( std::log10( K ) + 1 ) ) << std::setfill( '0' ) << k;
  stream << ".txt";

  return stream.str();
}

void usage()
{
  std::cerr << "Usage: clique-persistence-diagram FILE K\n"
            << "\n"
            << "Calculates the clique persistence diagram for FILE, which is\n"
            << "supposed to be a weighted graph. The K parameter denotes the\n"
            << "maximum dimension of a simplex for extracting a clique graph\n"
            << "and tracking persistence of clique communities.\n\n";
}

int main( int argc, char** argv )
{
  if( argc <= 2 )
  {
    usage();
    return -1;
  }

  std::string filename = argv[1];
  unsigned maxK        = static_cast<unsigned>( std::stoul( argv[2] ) );

  SimplicialComplex K;

  // Input -------------------------------------------------------------

  std::cerr << "* Reading '" << filename << "'...";

  if( aleph::utilities::extension( filename ) == ".gml" )
  {
    aleph::topology::io::GMLReader reader;
    reader( filename, K );
  }
  else
  {
    aleph::io::EdgeListReader reader;
    reader.setReadWeights( true );
    reader.setTrimLines( true );

    reader( filename, K );
  }

  std::cerr << "finished\n";

  DataType maxWeight = std::numeric_limits<DataType>::lowest();
  for( auto&& simplex : K )
    maxWeight = std::max( maxWeight, simplex.data() );

  // Expansion ---------------------------------------------------------

  aleph::geometry::RipsExpander<SimplicialComplex> ripsExpander;
  K = ripsExpander( K, maxK );
  K = ripsExpander.assignMaximumWeight( K );

  K.sort( aleph::filtrations::Data<Simplex>() );

  for( unsigned k = 1; k <= maxK; k++ )
  {
    std::cerr << "* Extracting " << k << "-cliques graph...";

    auto C
        = aleph::topology::getCliqueGraph( K, k );

    C.sort( aleph::filtrations::Data<Simplex>() );

    std::cerr << "finished\n";

    std::cerr << "* " << k << "-cliques graph has " << C.size() << " simplices\n";

    if( C.empty() )
    {
      std::cerr << "* Stopping here because no further cliques for processing exist\n";
      break;
    }

    auto pd
        = aleph::calculateZeroDimensionalPersistenceDiagram( C );

    // Stores the accumulated persistence of vertices. Persistence
    // accumulates if a vertex participates in a clique community.
    std::map<VertexType, double> accumulatedPersistenceMap;

    {
      for( auto&& point : pd )
      {
        // TODO:
        //   - Extract simplicial complex of given threshold
        //   - Calculate connected components
        //   - Extract connected component containing the creator simplex
        //   - Traverse the connected component and assign persistence

        auto epsilon = point.x();
      }
    }

    {
      using namespace aleph::utilities;
      auto outputFilename = formatOutput( "/tmp/" + stem( basename( filename ) ) + "_k", k, maxK );

      std::cerr << "* Storing output in '" << outputFilename << "'...\n";

      pd.removeDiagonal();

      std::transform( pd.begin(), pd.end(), pd.begin(),
                      [&maxWeight] ( const PersistenceDiagram::Point& p )
                      {
                        if( !std::isfinite( p.y() ) )
                          return PersistenceDiagram::Point( p.x(), maxWeight );
                        else
                          return p;
                      } );

      std::ofstream out( outputFilename );
      out << "# Original filename: " << filename << "\n";
      out << "# k                : " << k        << "\n";
      out << pd << "\n";
    }
  }
}
<|endoftext|>


<commit_before>#include "npc.h"
#include "room.h"
#include <iostream>

Npc::Npc(const char* npcName, const char* npcDescription, Room* loc) : Creature(npcName, npcDescription, loc)
{
	name = npcName;
	description = npcDescription;
	entityType = npc;
	location = loc;
	alive = true;
	aware = false;
}

Npc::~Npc()
{
}

void Npc::checkShip(const Room* playerLocation)
{
	if ((playerLocation->name == "Poopdeck" || playerLocation->name == "Main deck") && !aware)
	{
		aware = true;
		std::cout << std::endl;
		std::cout << "---------------------------------------------" << std::endl;
		std::cout << "Slinger, The Lookout: HEY YOU! What are you doing there? Climb to the crow's nest NOW!!" << std::endl;
		std::cout << "---------------------------------------------" << std::endl;
		std::cout << ">";
	}
}

void Npc::getMad(const Room* playerLocation)
{
	std::cout << std::endl;
	std::cout << "---------------------------------------------" << std::endl;
	if(playerLocation != location)
	{
		switch (npcMood)
		{
			case CALM:
				std::cout << "Slinger, The Lookout: I told you to climb here right now. I don't like to repeat things, dog. MOVE!!" << std::endl;
				npcMood = MAD;
				break;
			case MAD:
				std::cout << "Slinger, The Lookout: Do you thing that beeing in this ship for a month gives you permision to question my orders? Don't get me mad, son..." << std::endl;
				npcMood = VIOLENT;
				break;
			case VIOLENT:
				std::cout << "Slinger, The Lookout: Your choice. This is your last oportunity. (You hear the sound of a musket beeing loaded)" << std::endl;
				npcMood = KILL;
				break;
			case KILL:
				std::cout << "BANG!!" << std::endl;
				break;
		}
	}
	else
	{
		std::cout << "Slinger, The Lookout: Bla bla bla... (Boring complains about beeing out of bed... Seems like you only have one way to go)" << std::endl;
	}
	std::cout << "---------------------------------------------" << std::endl;
	std::cout << ">";
}<commit_msg>Enemy NPC now changes mood when stopping by his side<commit_after>#include "npc.h"
#include "room.h"
#include <iostream>

Npc::Npc(const char* npcName, const char* npcDescription, Room* loc) : Creature(npcName, npcDescription, loc)
{
	name = npcName;
	description = npcDescription;
	entityType = npc;
	location = loc;
	alive = true;
	aware = false;
}

Npc::~Npc()
{
}

void Npc::checkShip(const Room* playerLocation)
{
	if ((playerLocation->name == "Poopdeck" || playerLocation->name == "Main deck") && !aware)
	{
		aware = true;
		std::cout << std::endl;
		std::cout << "---------------------------------------------" << std::endl;
		std::cout << "Slinger, The Lookout: HEY YOU! What are you doing there? Climb to the crow's nest NOW!!" << std::endl;
		std::cout << "---------------------------------------------" << std::endl;
		std::cout << ">";
	}
}

void Npc::getMad(const Room* playerLocation)
{
	std::cout << std::endl;
	std::cout << "---------------------------------------------" << std::endl;
	if(playerLocation != location)
	{
		switch (npcMood)
		{
			case CALM:
				std::cout << "Slinger, The Lookout: I told you to climb here right now. I don't like to repeat things, dog. MOVE!!" << std::endl;
				npcMood = MAD;
				break;
			case MAD:
				std::cout << "Slinger, The Lookout: Do you thing that beeing in this ship for a month gives you permision to question my orders? Don't get me mad, son..." << std::endl;
				npcMood = VIOLENT;
				break;
			case VIOLENT:
				std::cout << "Slinger, The Lookout: Your choice. This is your last oportunity. (You hear the sound of a musket beeing loaded)" << std::endl;
				npcMood = KILL;
				break;
			case KILL:
				std::cout << "BANG!!" << std::endl;
				break;
		}
	}
	else
	{
		std::cout << "Slinger, The Lookout: Bla bla bla... (Boring complains about beeing out of bed... Seems like you only have one way to go)" << std::endl;
		if (npcMood == VIOLENT) npcMood = MAD;
		else if (npcMood == MAD) npcMood = CALM;
	}
	std::cout << "---------------------------------------------" << std::endl;
	std::cout << ">";
}<|endoftext|>


<commit_before>#include "StdAfx.h"
#include "Rw2Decoder.h"

/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

    This library 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 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; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/
namespace RawSpeed {

Rw2Decoder::Rw2Decoder(TiffIFD *rootIFD, FileMap* file) :
    RawDecoder(file), mRootIFD(rootIFD), input_start(0) {
      decoderVersion = 1;
}
Rw2Decoder::~Rw2Decoder(void) {
  if (input_start)
    delete input_start;
  input_start = 0;
  if (mRootIFD)
    delete mRootIFD;
  mRootIFD = NULL;
}

RawImage Rw2Decoder::decodeRawInternal() {

  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(PANASONIC_STRIPOFFSET);

  bool isOldPanasonic = FALSE;

  if (data.empty()) {
    if (!mRootIFD->hasEntryRecursive(STRIPOFFSETS))
      ThrowRDE("RW2 Decoder: No image data found");
    isOldPanasonic = TRUE;
    data = mRootIFD->getIFDsWithTag(STRIPOFFSETS);
  }

  TiffIFD* raw = data[0];
  uint32 height = raw->getEntry((TiffTag)3)->getShort();
  uint32 width = raw->getEntry((TiffTag)2)->getShort();

  if (isOldPanasonic) {
    ThrowRDE("Cannot decode old-style Panasonic RAW files");
    TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
    TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);

    if (offsets->count != 1) {
      ThrowRDE("RW2 Decoder: Multiple Strips found: %u", offsets->count);
    }
    int off = offsets->getInt();
    if (!mFile->isValid(off))
      ThrowRDE("Panasonic RAW Decoder: Invalid image data offset, cannot decode.");

    int count = counts->getInt();
    if (count != (int)(width*height*2))
      ThrowRDE("Panasonic RAW Decoder: Byte count is wrong.");

    if (!mFile->isValid(off+count))
      ThrowRDE("Panasonic RAW Decoder: Invalid image data offset, cannot decode.");

    mRaw->dim = iPoint2D(width, height);
    mRaw->createData();
    ByteStream input_start(mFile->getData(off), mFile->getSize() - off);
    iPoint2D pos(0, 0);
    readUncompressedRaw(input_start, mRaw->dim,pos, width*2, 16, BitOrder_Plain);

  } else {

    mRaw->dim = iPoint2D(width, height);
    mRaw->createData();
    TiffEntry *offsets = raw->getEntry(PANASONIC_STRIPOFFSET);

    if (offsets->count != 1) {
      ThrowRDE("RW2 Decoder: Multiple Strips found: %u", offsets->count);
    }

    load_flags = 0x2008;
    int off = offsets->getInt();

    if (!mFile->isValid(off))
      ThrowRDE("RW2 Decoder: Invalid image data offset, cannot decode.");

    input_start = new ByteStream(mFile->getData(off), mFile->getSize() - off);
    DecodeRw2();
  }
  return mRaw;
}

void Rw2Decoder::DecodeRw2() {
  startThreads();
}

void Rw2Decoder::decodeThreaded(RawDecoderThread * t) {
  int x, i, j, sh = 0, pred[2], nonz[2];
  int w = mRaw->dim.x / 14;
  uint32 y;

  bool zero_is_bad = false;
  map<string,string>::iterator zero_hint = hints.find("zero_is_bad");
  if (zero_hint != hints.end())
    zero_is_bad = true;

  /* 9 + 1/7 bits per pixel */
  int skip = w * 14 * t->start_y * 9;
  skip += w * 2 * t->start_y;
  skip /= 8;

  PanaBitpump bits(new ByteStream(input_start));
  bits.load_flags = load_flags;
  bits.skipBytes(skip);

  vector<uint32> zero_pos;
  for (y = t->start_y; y < t->end_y; y++) {
    ushort16* dest = (ushort16*)mRaw->getData(0, y);
    for (x = 0; x < w; x++) {
      pred[0] = pred[1] = nonz[0] = nonz[1] = 0;
      int u = 0;
      for (i = 0; i < 14; i++) {
        // Even pixels
        if (u == 2)
        {
          sh = 4 >> (3 - bits.getBits(2));
          u = -1;
        }
        if (nonz[0]) {
          if ((j = bits.getBits(8))) {
            if ((pred[0] -= 0x80 << sh) < 0 || sh == 4)
              pred[0] &= ~(-1 << sh);
            pred[0] += j << sh;
          }
        } else if ((nonz[0] = bits.getBits(8)) || i > 11)
          pred[0] = nonz[0] << 4 | bits.getBits(4);
        *dest++ = pred[0];
        if (zero_is_bad && 0 == pred[0])
          zero_pos.push_back((y<<16) | (x*14+i));

        // Odd pixels
        i++;
        u++;
        if (u == 2)
        {
          sh = 4 >> (3 - bits.getBits(2));
          u = -1;
        }
        if (nonz[1]) {
          if ((j = bits.getBits(8))) {
            if ((pred[1] -= 0x80 << sh) < 0 || sh == 4)
              pred[1] &= ~(-1 << sh);
            pred[1] += j << sh;
          }
        } else if ((nonz[1] = bits.getBits(8)) || i > 11)
          pred[1] = nonz[1] << 4 | bits.getBits(4);
        *dest++ = pred[1];
        if (zero_is_bad && 0 == pred[1])
          zero_pos.push_back((y<<16) | (x*14+i));
        u++;
      }
    }
  }
  if (zero_is_bad && !zero_pos.empty()) {
    pthread_mutex_lock(&mRaw->mBadPixelMutex);
    mRaw->mBadPixelPositions.insert(mRaw->mBadPixelPositions.end(), zero_pos.begin(), zero_pos.end());
    pthread_mutex_unlock(&mRaw->mBadPixelMutex);
  }
}

void Rw2Decoder::checkSupportInternal(CameraMetaData *meta) {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);
  if (data.empty())
    ThrowRDE("RW2 Support check: Model name found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  if (!this->checkCameraSupported(meta, make, model, guessMode()))
    this->checkCameraSupported(meta, make, model, "");
}

void Rw2Decoder::decodeMetaDataInternal(CameraMetaData *meta) {
  mRaw->cfa.setCFA(CFA_BLUE, CFA_GREEN, CFA_GREEN2, CFA_RED);
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);

  if (data.empty())
    ThrowRDE("RW2 Meta Decoder: Model name not found");
  if (!data[0]->hasEntry(MAKE))
    ThrowRDE("RW2 Support: Make name not found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  string mode = guessMode();
  int iso = 0;
  if (mRootIFD->hasEntryRecursive(PANASONIC_ISO_SPEED))
    iso = mRootIFD->getEntryRecursive(PANASONIC_ISO_SPEED)->getInt();

  if (this->checkCameraSupported(meta, make, model, mode)) {
    setMetaData(meta, make, model, mode, iso);
  } else {
    mRaw->mode = mode;
    _RPT1(0, "Mode not found in DB: %s", mode.c_str());
    setMetaData(meta, make, model, "", iso);
  }
}

std::string Rw2Decoder::guessMode() {
  float ratio = 3.0f / 2.0f;  // Default

  if (!mRaw->isAllocated())
    return "";

  ratio = (float)mRaw->dim.x / (float)mRaw->dim.y;

  float min_diff = fabs(ratio - 16.0f / 9.0f);
  std::string closest_match = "16:9";

  float t = fabs(ratio - 3.0f / 2.0f);
  if (t < min_diff) {
    closest_match = "3:2";
    min_diff  = t;
  }

  t = fabs(ratio - 4.0f / 3.0f);
  if (t < min_diff) {
    closest_match =  "4:3";
    min_diff  = t;
  }

  t = fabs(ratio - 1.0f);
  if (t < min_diff) {
    closest_match = "1:1";
    min_diff  = t;
  }
  _RPT1(0, "Mode guess: '%s'\n", closest_match.c_str());
  return closest_match;
}

PanaBitpump::PanaBitpump(ByteStream* _input) : input(_input), vbits(0) {
}

PanaBitpump::~PanaBitpump() {
  if (input)
    delete input;
  input = 0;
}

void PanaBitpump::skipBytes(int bytes) {
  int blocks = (bytes / 0x4000) * 0x4000;
  input->skipBytes(blocks);
  for (int i = blocks; i < bytes; i++)
    getBits(8);
}

uint32 PanaBitpump::getBits(int nbits) {
  int byte;

  if (!vbits) {
    /* On truncated files this routine will just return just for the truncated
    * part of the file. Since there is no chance of affecting output buffer
    * size we allow the decoder to decode this
    */
    if (input->getRemainSize() < 0x4000 - load_flags) {
      memcpy(buf + load_flags, input->getData(), input->getRemainSize());
      input->skipBytes(input->getRemainSize());
    } else {
      memcpy(buf + load_flags, input->getData(), 0x4000 - load_flags);
      input->skipBytes(0x4000 - load_flags);
      if (input->getRemainSize() < load_flags) {
        memcpy(buf, input->getData(), input->getRemainSize());
        input->skipBytes(input->getRemainSize());
      } else {
        memcpy(buf, input->getData(), load_flags);
        input->skipBytes(load_flags);
      }
    }
  }
  vbits = (vbits - nbits) & 0x1ffff;
  byte = vbits >> 3 ^ 0x3ff0;
  return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits);
}

} // namespace RawSpeed
<commit_msg>Read blacklevels from Panasonic metadata.<commit_after>#include "StdAfx.h"
#include "Rw2Decoder.h"

/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

    This library 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 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; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/
namespace RawSpeed {

Rw2Decoder::Rw2Decoder(TiffIFD *rootIFD, FileMap* file) :
    RawDecoder(file), mRootIFD(rootIFD), input_start(0) {
      decoderVersion = 1;
}
Rw2Decoder::~Rw2Decoder(void) {
  if (input_start)
    delete input_start;
  input_start = 0;
  if (mRootIFD)
    delete mRootIFD;
  mRootIFD = NULL;
}

RawImage Rw2Decoder::decodeRawInternal() {

  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(PANASONIC_STRIPOFFSET);

  bool isOldPanasonic = FALSE;

  if (data.empty()) {
    if (!mRootIFD->hasEntryRecursive(STRIPOFFSETS))
      ThrowRDE("RW2 Decoder: No image data found");
    isOldPanasonic = TRUE;
    data = mRootIFD->getIFDsWithTag(STRIPOFFSETS);
  }

  TiffIFD* raw = data[0];
  uint32 height = raw->getEntry((TiffTag)3)->getShort();
  uint32 width = raw->getEntry((TiffTag)2)->getShort();

  if (isOldPanasonic) {
    ThrowRDE("Cannot decode old-style Panasonic RAW files");
    TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
    TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);

    if (offsets->count != 1) {
      ThrowRDE("RW2 Decoder: Multiple Strips found: %u", offsets->count);
    }
    int off = offsets->getInt();
    if (!mFile->isValid(off))
      ThrowRDE("Panasonic RAW Decoder: Invalid image data offset, cannot decode.");

    int count = counts->getInt();
    if (count != (int)(width*height*2))
      ThrowRDE("Panasonic RAW Decoder: Byte count is wrong.");

    if (!mFile->isValid(off+count))
      ThrowRDE("Panasonic RAW Decoder: Invalid image data offset, cannot decode.");

    mRaw->dim = iPoint2D(width, height);
    mRaw->createData();
    ByteStream input_start(mFile->getData(off), mFile->getSize() - off);
    iPoint2D pos(0, 0);
    readUncompressedRaw(input_start, mRaw->dim,pos, width*2, 16, BitOrder_Plain);

  } else {

    mRaw->dim = iPoint2D(width, height);
    mRaw->createData();
    TiffEntry *offsets = raw->getEntry(PANASONIC_STRIPOFFSET);

    if (offsets->count != 1) {
      ThrowRDE("RW2 Decoder: Multiple Strips found: %u", offsets->count);
    }

    load_flags = 0x2008;
    int off = offsets->getInt();

    if (!mFile->isValid(off))
      ThrowRDE("RW2 Decoder: Invalid image data offset, cannot decode.");

    input_start = new ByteStream(mFile->getData(off), mFile->getSize() - off);
    DecodeRw2();
  }
  // Read blacklevels
  if (raw->hasEntry((TiffTag)0x1c) && raw->hasEntry((TiffTag)0x1d) && raw->hasEntry((TiffTag)0x1e)) {
    mRaw->blackLevelSeparate[0] = raw->getEntry((TiffTag)0x1c)->getInt() + 15;
    mRaw->blackLevelSeparate[1] = mRaw->blackLevelSeparate[2] = raw->getEntry((TiffTag)0x1d)->getInt() + 15;
    mRaw->blackLevelSeparate[3] = raw->getEntry((TiffTag)0x1e)->getInt() + 15;
  }
  return mRaw;
}

void Rw2Decoder::DecodeRw2() {
  startThreads();
}

void Rw2Decoder::decodeThreaded(RawDecoderThread * t) {
  int x, i, j, sh = 0, pred[2], nonz[2];
  int w = mRaw->dim.x / 14;
  uint32 y;

  bool zero_is_bad = false;
  map<string,string>::iterator zero_hint = hints.find("zero_is_bad");
  if (zero_hint != hints.end())
    zero_is_bad = true;

  /* 9 + 1/7 bits per pixel */
  int skip = w * 14 * t->start_y * 9;
  skip += w * 2 * t->start_y;
  skip /= 8;

  PanaBitpump bits(new ByteStream(input_start));
  bits.load_flags = load_flags;
  bits.skipBytes(skip);

  vector<uint32> zero_pos;
  for (y = t->start_y; y < t->end_y; y++) {
    ushort16* dest = (ushort16*)mRaw->getData(0, y);
    for (x = 0; x < w; x++) {
      pred[0] = pred[1] = nonz[0] = nonz[1] = 0;
      int u = 0;
      for (i = 0; i < 14; i++) {
        // Even pixels
        if (u == 2)
        {
          sh = 4 >> (3 - bits.getBits(2));
          u = -1;
        }
        if (nonz[0]) {
          if ((j = bits.getBits(8))) {
            if ((pred[0] -= 0x80 << sh) < 0 || sh == 4)
              pred[0] &= ~(-1 << sh);
            pred[0] += j << sh;
          }
        } else if ((nonz[0] = bits.getBits(8)) || i > 11)
          pred[0] = nonz[0] << 4 | bits.getBits(4);
        *dest++ = pred[0];
        if (zero_is_bad && 0 == pred[0])
          zero_pos.push_back((y<<16) | (x*14+i));

        // Odd pixels
        i++;
        u++;
        if (u == 2)
        {
          sh = 4 >> (3 - bits.getBits(2));
          u = -1;
        }
        if (nonz[1]) {
          if ((j = bits.getBits(8))) {
            if ((pred[1] -= 0x80 << sh) < 0 || sh == 4)
              pred[1] &= ~(-1 << sh);
            pred[1] += j << sh;
          }
        } else if ((nonz[1] = bits.getBits(8)) || i > 11)
          pred[1] = nonz[1] << 4 | bits.getBits(4);
        *dest++ = pred[1];
        if (zero_is_bad && 0 == pred[1])
          zero_pos.push_back((y<<16) | (x*14+i));
        u++;
      }
    }
  }
  if (zero_is_bad && !zero_pos.empty()) {
    pthread_mutex_lock(&mRaw->mBadPixelMutex);
    mRaw->mBadPixelPositions.insert(mRaw->mBadPixelPositions.end(), zero_pos.begin(), zero_pos.end());
    pthread_mutex_unlock(&mRaw->mBadPixelMutex);
  }
}

void Rw2Decoder::checkSupportInternal(CameraMetaData *meta) {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);
  if (data.empty())
    ThrowRDE("RW2 Support check: Model name found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  if (!this->checkCameraSupported(meta, make, model, guessMode()))
    this->checkCameraSupported(meta, make, model, "");
}

void Rw2Decoder::decodeMetaDataInternal(CameraMetaData *meta) {
  mRaw->cfa.setCFA(CFA_BLUE, CFA_GREEN, CFA_GREEN2, CFA_RED);
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);

  if (data.empty())
    ThrowRDE("RW2 Meta Decoder: Model name not found");
  if (!data[0]->hasEntry(MAKE))
    ThrowRDE("RW2 Support: Make name not found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  string mode = guessMode();
  int iso = 0;
  if (mRootIFD->hasEntryRecursive(PANASONIC_ISO_SPEED))
    iso = mRootIFD->getEntryRecursive(PANASONIC_ISO_SPEED)->getInt();

  if (this->checkCameraSupported(meta, make, model, mode)) {
    setMetaData(meta, make, model, mode, iso);
  } else {
    mRaw->mode = mode;
    _RPT1(0, "Mode not found in DB: %s", mode.c_str());
    setMetaData(meta, make, model, "", iso);
  }
}

std::string Rw2Decoder::guessMode() {
  float ratio = 3.0f / 2.0f;  // Default

  if (!mRaw->isAllocated())
    return "";

  ratio = (float)mRaw->dim.x / (float)mRaw->dim.y;

  float min_diff = fabs(ratio - 16.0f / 9.0f);
  std::string closest_match = "16:9";

  float t = fabs(ratio - 3.0f / 2.0f);
  if (t < min_diff) {
    closest_match = "3:2";
    min_diff  = t;
  }

  t = fabs(ratio - 4.0f / 3.0f);
  if (t < min_diff) {
    closest_match =  "4:3";
    min_diff  = t;
  }

  t = fabs(ratio - 1.0f);
  if (t < min_diff) {
    closest_match = "1:1";
    min_diff  = t;
  }
  _RPT1(0, "Mode guess: '%s'\n", closest_match.c_str());
  return closest_match;
}

PanaBitpump::PanaBitpump(ByteStream* _input) : input(_input), vbits(0) {
}

PanaBitpump::~PanaBitpump() {
  if (input)
    delete input;
  input = 0;
}

void PanaBitpump::skipBytes(int bytes) {
  int blocks = (bytes / 0x4000) * 0x4000;
  input->skipBytes(blocks);
  for (int i = blocks; i < bytes; i++)
    getBits(8);
}

uint32 PanaBitpump::getBits(int nbits) {
  int byte;

  if (!vbits) {
    /* On truncated files this routine will just return just for the truncated
    * part of the file. Since there is no chance of affecting output buffer
    * size we allow the decoder to decode this
    */
    if (input->getRemainSize() < 0x4000 - load_flags) {
      memcpy(buf + load_flags, input->getData(), input->getRemainSize());
      input->skipBytes(input->getRemainSize());
    } else {
      memcpy(buf + load_flags, input->getData(), 0x4000 - load_flags);
      input->skipBytes(0x4000 - load_flags);
      if (input->getRemainSize() < load_flags) {
        memcpy(buf, input->getData(), input->getRemainSize());
        input->skipBytes(input->getRemainSize());
      } else {
        memcpy(buf, input->getData(), load_flags);
        input->skipBytes(load_flags);
      }
    }
  }
  vbits = (vbits - nbits) & 0x1ffff;
  byte = vbits >> 3 ^ 0x3ff0;
  return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits);
}

} // namespace RawSpeed
<|endoftext|>


<commit_before>/* test_minimizer.cpp - Test Adept minimizer with N-dimensional Rosenbrock function

  Copyright (C) 2020 ECMWF

  Copying and distribution of this file, with or without modification,
  are permitted in any medium without royalty provided the copyright
  notice and this notice are preserved.  This file is offered as-is,
  without any warranty.
*/

//#include <string> // for std::stoi in C++11
#include <cstdio>  // for std::sscanf in C++98
#include <iostream>
#include <adept_optimize.h>

// Set this to a large or small number to test if the minimization
// algorithms are immune to the absolute scaling of the cost function
#define COST_SCALING 1.0

using namespace adept;

class RosenbrockN : public Optimizable {
public:

  RosenbrockN() : ls_iteration_(0) {}

  int ls_iteration_; // Line search iteration

  // N-dimensional Rosenbrock function can be expressed as the sum of
  // the squared elements of vector y(x) defined as follows.  This
  // form facilitates the calculation of the Hessian from the Jacobian
  // dy/dx.  It is templated so that can be called either with a
  // passive "Vector" or active "aVector" argument.
  template <bool IsActive>
  Array<1,Real,IsActive> calc_y(const Array<1,Real,IsActive>& x) {
    int nx = x.size();
    Array<1,Real,IsActive> y((nx-1)*2);
    for (int ix = 0; ix < nx-1; ++ix) {
      y(ix*2)   = 10.0 * (x(ix+1)-x(ix)*x(ix));
      y(ix*2+1) = 1.0 - x(ix);
    }
    y *= sqrt(2.0 * COST_SCALING);
    return y;
  }

  virtual void report_progress(int niter, const adept::Vector& x,
			       Real cost, Real gnorm) {
    ls_iteration_ = 0;
    std::cout << "Iteration " << niter
	      << ": cost=" << cost << ", gnorm=" << gnorm << "\n";
  }

  void state_to_stderr(const adept::Vector& x, Real cost) {

    // For plotting progress, direct standard error to a text file
    std::cerr << ls_iteration_ << " ";
    for (int ix = 0; ix < x.size(); ++ix) {
      std::cerr << x(ix) << " ";
    }
    std::cerr << cost << "\n";
    ++ls_iteration_;
  }

  void final_state_to_stderr(const adept::Vector& x, Real cost) {
    ls_iteration_ = -1;
    state_to_stderr(x, cost);
  }

  virtual bool provides_derivative(int order) {
    if (order >= 0 && order <= 2) {
      return true;
    }
    else {
      return false;
    }
  }

  virtual Real calc_cost_function(const Vector& x) {
    //std::cout << "  test x: " << x << "\n";
    Vector y = calc_y(x);
    Real cost = 0.5*sum(y*y);
    state_to_stderr(x,cost);
    return cost;
  }

  virtual Real calc_cost_function_gradient(const Vector& x,
					   Vector gradient) {
    Stack stack;
    aVector xactive = x;
    stack.new_recording();
    aVector y = calc_y(xactive);
    aReal cost = 0.5*sum(y*y);
    cost.set_gradient(1.0);
    stack.reverse();
    gradient = xactive.get_gradient();
    state_to_stderr(x,value(cost));
    return value(cost);
  }

  virtual Real calc_cost_function_gradient_hessian(const Vector& x,
						   Vector gradient,
						   SymmMatrix& hessian) {
    Stack stack;
    aVector xactive = x;
    stack.new_recording();
    aVector y = calc_y(xactive);
    aReal cost = 0.5*sum(y*y);
    stack.independent(xactive);
    stack.dependent(y);
    Matrix jac = stack.jacobian();
    hessian  = jac.T() ** jac;
    gradient = jac.T() ** value(y);
    state_to_stderr(x,value(cost));
    return value(cost);
  }

};

int
main(int argc, const char* argv[])
{

  if (!adept::have_linear_algebra()) {
    std::cout << "Adept compiled without linear-algebra support: minimizer not available\n";
    return 0;
  }

  RosenbrockN rosenbrock;
  Minimizer minimizer(MINIMIZER_ALGORITHM_LEVENBERG_MARQUARDT);
  // The convergence criterion should be changed in accordance with
  // the cost function scaling
  minimizer.set_converged_gradient_norm(0.1*COST_SCALING);
  int nx = 2;
  if (argc > 1) {
    // nx = std::stoi(argv[1]);
    std::sscanf(argv[1], "%d", &nx);
    if (argc > 2) {
      minimizer.set_algorithm(argv[2]);
      if (argc > 3) {
	int max_it;
	// max_it = std::stof(argv[3]);
	std::sscanf(argv[3], "%d", &max_it);
	minimizer.set_max_iterations(max_it);
	if (argc > 4) {
	  double converged_grad_norm;
	  //converged_grad_norm = std::stof(argv[4]);
	  std::sscanf(argv[4], "%lf", &converged_grad_norm);
	  minimizer.set_converged_gradient_norm(converged_grad_norm);
	}
      }
    }
  }
  else {
    std::cout << "Usage: " << argv[0] << " [nx] [Levenberg|Levenberg-Marquardt|L-BFGS|Conjugate-Gradient] [max_iterations] [converged_gradient_norm]\n";
  }

  //minimizer.set_levenberg_damping_start(0.0);
  //minimizer.set_max_step_size(1.0);
  //  minimizer.set_levenberg_damping_multiplier(3.0, 5.0);
  minimizer.ensure_updated_state(2);

  std::cout << "Minimizing " << nx << "-dimensional Rosenbrock function\n";
  std::cout << "Algorithm: " << minimizer.algorithm_name() << "\n";
  std::cout << "Maximum iterations: " << minimizer.max_iterations() << "\n";
  std::cout << "Converged gradient norm: " << minimizer.converged_gradient_norm() << "\n";

  // Initial state vector
  Vector x(nx);
  // Standard start
  x = -3.0;
  // Trickier start (other end of the banana)
  //x = -3.0; x(1) = 3.0;
  // Near other minima in higher dimensions
  //x = 1.0; x(0) = -1.0;

  bool is_bounded = false;
  MinimizerStatus status;

  if (is_bounded) {
    x = -3.0; x(1) = 3.0;
    Vector x_lower, x_upper;
    adept::minimizer_initialize_bounds(nx, x_lower, x_upper);
    x_upper(1) = 2.0;
    x_lower(1) = 0.2;
    status = minimizer.minimize(rosenbrock, x, x_lower, x_upper);
  }
  else {
    status = minimizer.minimize(rosenbrock, x);
  }
  //rosenbrock.final_state_to_stderr(x, minimizer.cost_function());

  std::cout << "Status: " << minimizer_status_string(status) << "\n";
  std::cout << "Solution: x=" << x << "\n";
  std::cout << "Number of samples: " << minimizer.n_samples() << "\n";

  return static_cast<int>(status);
}
<commit_msg>Updated test_minimizer settings so that bounded reproduces video on web site<commit_after>/* test_minimizer.cpp - Test Adept minimizer with N-dimensional Rosenbrock function

  Copyright (C) 2020 ECMWF

  Copying and distribution of this file, with or without modification,
  are permitted in any medium without royalty provided the copyright
  notice and this notice are preserved.  This file is offered as-is,
  without any warranty.
*/

//#include <string> // for std::stoi in C++11
#include <cstdio>  // for std::sscanf in C++98
#include <iostream>
#include <adept_optimize.h>

// Set this to a large or small number to test if the minimization
// algorithms are immune to the absolute scaling of the cost function
#define COST_SCALING 1.0

using namespace adept;

class RosenbrockN : public Optimizable {
public:

  RosenbrockN() : ls_iteration_(0) {}

  int ls_iteration_; // Line search iteration

  // N-dimensional Rosenbrock function can be expressed as the sum of
  // the squared elements of vector y(x) defined as follows.  This
  // form facilitates the calculation of the Hessian from the Jacobian
  // dy/dx.  It is templated so that can be called either with a
  // passive "Vector" or active "aVector" argument.
  template <bool IsActive>
  Array<1,Real,IsActive> calc_y(const Array<1,Real,IsActive>& x) {
    int nx = x.size();
    Array<1,Real,IsActive> y((nx-1)*2);
    for (int ix = 0; ix < nx-1; ++ix) {
      y(ix*2)   = 10.0 * (x(ix+1)-x(ix)*x(ix));
      y(ix*2+1) = 1.0 - x(ix);
    }
    y *= sqrt(2.0 * COST_SCALING);
    return y;
  }

  virtual void report_progress(int niter, const adept::Vector& x,
			       Real cost, Real gnorm) {
    ls_iteration_ = 0;
    std::cout << "Iteration " << niter
	      << ": cost=" << cost << ", gnorm=" << gnorm << "\n";
  }

  void state_to_stderr(const adept::Vector& x, Real cost) {

    // For plotting progress, direct standard error to a text file
    std::cerr << ls_iteration_ << " ";
    for (int ix = 0; ix < x.size(); ++ix) {
      std::cerr << x(ix) << " ";
    }
    std::cerr << cost << "\n";
    ++ls_iteration_;
  }

  void final_state_to_stderr(const adept::Vector& x, Real cost) {
    ls_iteration_ = -1;
    state_to_stderr(x, cost);
  }

  virtual bool provides_derivative(int order) {
    if (order >= 0 && order <= 2) {
      return true;
    }
    else {
      return false;
    }
  }

  virtual Real calc_cost_function(const Vector& x) {
    //std::cout << "  test x: " << x << "\n";
    Vector y = calc_y(x);
    Real cost = 0.5*sum(y*y);
    state_to_stderr(x,cost);
    return cost;
  }

  virtual Real calc_cost_function_gradient(const Vector& x,
					   Vector gradient) {
    Stack stack;
    aVector xactive = x;
    stack.new_recording();
    aVector y = calc_y(xactive);
    aReal cost = 0.5*sum(y*y);
    cost.set_gradient(1.0);
    stack.reverse();
    gradient = xactive.get_gradient();
    state_to_stderr(x,value(cost));
    return value(cost);
  }

  virtual Real calc_cost_function_gradient_hessian(const Vector& x,
						   Vector gradient,
						   SymmMatrix& hessian) {
    Stack stack;
    aVector xactive = x;
    stack.new_recording();
    aVector y = calc_y(xactive);
    aReal cost = 0.5*sum(y*y);
    stack.independent(xactive);
    stack.dependent(y);
    Matrix jac = stack.jacobian();
    hessian  = jac.T() ** jac;
    gradient = jac.T() ** value(y);
    state_to_stderr(x,value(cost));
    return value(cost);
  }

};

int
main(int argc, const char* argv[])
{

  if (!adept::have_linear_algebra()) {
    std::cout << "Adept compiled without linear-algebra support: minimizer not available\n";
    return 0;
  }

  RosenbrockN rosenbrock;
  Minimizer minimizer(MINIMIZER_ALGORITHM_LEVENBERG_MARQUARDT);
  // The convergence criterion should be changed in accordance with
  // the cost function scaling
  minimizer.set_converged_gradient_norm(0.1*COST_SCALING);
  int nx = 2;
  if (argc > 1) {
    // nx = std::stoi(argv[1]);
    std::sscanf(argv[1], "%d", &nx);
    if (argc > 2) {
      minimizer.set_algorithm(argv[2]);
      if (argc > 3) {
	int max_it;
	// max_it = std::stof(argv[3]);
	std::sscanf(argv[3], "%d", &max_it);
	minimizer.set_max_iterations(max_it);
	if (argc > 4) {
	  double converged_grad_norm;
	  //converged_grad_norm = std::stof(argv[4]);
	  std::sscanf(argv[4], "%lf", &converged_grad_norm);
	  minimizer.set_converged_gradient_norm(converged_grad_norm);
	}
      }
    }
  }
  else {
    std::cout << "Usage: " << argv[0] << " [nx] [Levenberg|Levenberg-Marquardt|L-BFGS|Conjugate-Gradient] [max_iterations] [converged_gradient_norm]\n";
  }

  minimizer.set_levenberg_damping_start(0.25);
  //minimizer.set_max_step_size(1.0);
  //  minimizer.set_levenberg_damping_multiplier(3.0, 5.0);
  minimizer.ensure_updated_state(2);

  std::cout << "Minimizing " << nx << "-dimensional Rosenbrock function\n";
  std::cout << "Algorithm: " << minimizer.algorithm_name() << "\n";
  std::cout << "Maximum iterations: " << minimizer.max_iterations() << "\n";
  std::cout << "Converged gradient norm: " << minimizer.converged_gradient_norm() << "\n";

  // Initial state vector
  Vector x(nx);
  // Standard start
  x = -3.0;
  // Trickier start (other end of the banana)
  //x = -3.0; x(1) = 3.0;
  // Near other minima in higher dimensions
  //x = 1.0; x(0) = -1.0;

  bool is_bounded = false;
  MinimizerStatus status;

  if (is_bounded) {
    //    x = -3.0; x(1) = 3.0;
    x = -0.75; x(1) = 3.0;
    Vector x_lower, x_upper;
    adept::minimizer_initialize_bounds(nx, x_lower, x_upper);
    // x_upper(1) = 2.0;   x_lower(1) = 0.2;
    x_lower(0) = -1;
    status = minimizer.minimize(rosenbrock, x, x_lower, x_upper);
  }
  else {
    status = minimizer.minimize(rosenbrock, x);
  }
  //rosenbrock.final_state_to_stderr(x, minimizer.cost_function());

  std::cout << "Status: " << minimizer_status_string(status) << "\n";
  std::cout << "Solution: x=" << x << "\n";
  std::cout << "Number of samples: " << minimizer.n_samples() << "\n";

  return static_cast<int>(status);
}
<|endoftext|>