<commit_before>#include "pch.h"
#include "DeviceManager.h"

#include "DspMatrix.h"

namespace SaneAudioRenderer
{
    namespace
    {
        const auto WindowClass = L"SaneAudioRenderer::DeviceManager";
        const auto WindowTitle = L"";

        enum
        {
            WM_CHECK_BITSTREAM_FORMAT = WM_USER + 100,
            WM_CREATE_DEVICE,
        };

        template <class T>
        bool IsLastInstance(T& smartPointer)
        {
            bool ret = (smartPointer.GetInterfacePtr()->AddRef() == 2);
            smartPointer.GetInterfacePtr()->Release();
            return ret;
        }

        WAVEFORMATEXTENSIBLE BuildWaveFormatExt(GUID formatGuid, uint32_t formatBits, WORD formatExtProps,
                                                uint32_t rate, uint32_t channelCount, DWORD channelMask)
        {
            WAVEFORMATEXTENSIBLE ret;
            ret.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
            ret.Format.nChannels = channelCount;
            ret.Format.nSamplesPerSec = rate;
            ret.Format.nAvgBytesPerSec = formatBits / 8 * rate * channelCount;
            ret.Format.nBlockAlign = formatBits / 8 * channelCount;
            ret.Format.wBitsPerSample = formatBits;
            ret.Format.cbSize = 22;
            ret.Samples.wValidBitsPerSample = formatExtProps;
            ret.dwChannelMask = channelMask;
            ret.SubFormat = formatGuid;
            return ret;
        }

        std::shared_ptr<std::wstring> GetDevicePropertyString(IPropertyStore* pStore, REFPROPERTYKEY key)
        {
            assert(pStore);

            PROPVARIANT prop;
            PropVariantInit(&prop);
            ThrowIfFailed(pStore->GetValue(key, &prop));
            auto ret = std::make_shared<std::wstring>(prop.pwszVal);
            PropVariantClear(&prop);

            return ret;
        }

        void CreateAudioClient(AudioDevice& output, ISettings* pSettings)
        {
            assert(pSettings);

            std::unique_ptr<wchar_t, CoTaskMemFreeDeleter> deviceName;

            {
                output.settingsSerial = pSettings->GetSerial();

                LPWSTR pDeviceName = nullptr;
                BOOL exclusive;
                ThrowIfFailed(pSettings->GetOuputDevice(&pDeviceName, &exclusive));

                deviceName.reset(pDeviceName);
                output.exclusive = !!exclusive;
            }

            IMMDeviceEnumeratorPtr enumerator;
            ThrowIfFailed(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr,
                                           CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&enumerator)));

            IMMDevicePtr device;
            IPropertyStorePtr devicePropertyStore;

            if (!deviceName || !*deviceName)
            {
                output.default = true;
                ThrowIfFailed(enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device));
                ThrowIfFailed(device->OpenPropertyStore(STGM_READ, &devicePropertyStore));
                output.friendlyName = GetDevicePropertyString(devicePropertyStore, PKEY_Device_FriendlyName);
            }
            else
            {
                output.default = false;

                IMMDeviceCollectionPtr collection;
                ThrowIfFailed(enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &collection));

                UINT count = 0;
                ThrowIfFailed(collection->GetCount(&count));

                for (UINT i = 0; i < count; i++)
                {
                    ThrowIfFailed(collection->Item(i, &device));
                    ThrowIfFailed(device->OpenPropertyStore(STGM_READ, &devicePropertyStore));
                    output.friendlyName = GetDevicePropertyString(devicePropertyStore, PKEY_Device_FriendlyName);

                    if (wcscmp(deviceName.get(), output.friendlyName->c_str()))
                    {
                        device = nullptr;
                        devicePropertyStore = nullptr;
                        output.friendlyName = nullptr;
                    }
                }
            }

            if (!device)
                return;

            output.adapterName = GetDevicePropertyString(devicePropertyStore, PKEY_DeviceInterface_FriendlyName);
            output.endpointName = GetDevicePropertyString(devicePropertyStore, PKEY_Device_DeviceDesc);

            ThrowIfFailed(device->Activate(__uuidof(IAudioClient),
                                           CLSCTX_INPROC_SERVER, nullptr, (void**)&output.audioClient));
        }
    }

    DeviceManager::DeviceManager(HRESULT& result)
    {
        if (FAILED(result))
            return;

        m_hThread = (HANDLE)_beginthreadex(nullptr, 0, StaticThreadProc<DeviceManager>, this, 0, nullptr);

        if (m_hThread == NULL || !m_windowInitialized.get_future().get())
            result = E_FAIL;
    }

    DeviceManager::~DeviceManager()
    {
        m_queuedDestroy = true;
        PostMessage(m_hWindow, WM_DESTROY, 0, 0);
        WaitForSingleObject(m_hThread, INFINITE);
        CloseHandle(m_hThread);
        UnregisterClass(WindowClass, GetModuleHandle(nullptr));
    }

    bool DeviceManager::BitstreamFormatSupported(SharedWaveFormat format, ISettings* pSettings)
    {
        assert(format);
        assert(pSettings);

        m_checkBitstreamFormat = format;
        m_checkBitstreamSettings = pSettings;
        m_queuedCheckBitstream = true;

        bool ret = (SendMessage(m_hWindow, WM_CHECK_BITSTREAM_FORMAT, 0, 0) == 0);

        m_checkBitstreamFormat = nullptr;
        m_checkBitstreamSettings = nullptr;
        assert(m_queuedCheckBitstream == false);

        return ret;
    }

    bool DeviceManager::CreateDevice(AudioDevice& device, SharedWaveFormat format, ISettings* pSettings)
    {
        assert(format);
        assert(pSettings);

        m_createDeviceFormat = format;
        m_createDeviceSettings = pSettings;
        m_queuedCreateDevice = true;

        bool ret = (SendMessage(m_hWindow, WM_CREATE_DEVICE, 0, 0) == 0);

        m_createDeviceFormat = nullptr;
        m_createDeviceSettings = nullptr;
        assert(m_queuedCreateDevice == false);

        device = m_device;

        return ret;
    }

    void DeviceManager::ReleaseDevice()
    {
        auto areLastInstances = [this]
        {
            if (m_device.audioClock && !IsLastInstance(m_device.audioClock))
                return false;

            m_device.audioClock = nullptr;

            if (m_device.audioRenderClient && !IsLastInstance(m_device.audioRenderClient))
                return false;

            m_device.audioRenderClient = nullptr;

            if (m_device.audioClient && !IsLastInstance(m_device.audioClient))
                return false;

            return true;
        };
        assert(areLastInstances());

        m_device = {};
    }

    LRESULT DeviceManager::OnCheckBitstreamFormat()
    {
        if (!m_queuedCheckBitstream)
            return 1;

        assert(m_checkBitstreamFormat);
        assert(m_checkBitstreamSettings);
        m_queuedCheckBitstream = false;

        try
        {
            AudioDevice device = {};

            CreateAudioClient(device, m_checkBitstreamSettings);

            if (!m_device.audioClient)
                return 1;

            return SUCCEEDED(m_device.audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,
                                                                     &(*m_checkBitstreamFormat), nullptr)) ? 0 : 1;
        }
        catch (HRESULT)
        {
            return 1;
        }
    }

    LRESULT DeviceManager::OnCreateDevice()
    {
        if (!m_queuedCreateDevice)
            return 1;

        assert(m_createDeviceFormat);
        assert(m_createDeviceSettings);
        m_queuedCreateDevice = false;

        ReleaseDevice();
        try
        {
            CreateAudioClient(m_device, m_createDeviceSettings);

            if (!m_device.audioClient)
                return 1;

            WAVEFORMATEX* pFormat;
            ThrowIfFailed(m_device.audioClient->GetMixFormat(&pFormat));
            SharedWaveFormat mixFormat(pFormat, CoTaskMemFreeDeleter());

            m_device.bufferDuration = 200;

            if (DspFormatFromWaveFormat(*m_createDeviceFormat) == DspFormat::Unknown)
            {
                // Exclusive bitstreaming.
                if (!m_device.exclusive)
                    return 1;

                m_device.dspFormat = DspFormat::Unknown;
                m_device.waveFormat = m_createDeviceFormat;
            }
            else if (m_device.exclusive)
            {
                // Exclusive.
                auto inputRate = m_createDeviceFormat->nSamplesPerSec;
                auto mixRate = mixFormat->nSamplesPerSec;
                auto mixChannels = mixFormat->nChannels;
                auto mixMask = DspMatrix::GetChannelMask(*mixFormat);

                auto priorities = make_array(
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32, 32, inputRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        32, 32, inputRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        24, 24, inputRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        32, 24, inputRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        16, 16, inputRate, mixChannels, mixMask),

                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32, 32, mixRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        32, 32, mixRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        24, 24, mixRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        32, 24, mixRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        16, 16, mixRate, mixChannels, mixMask)
                );

                for (const auto& f : priorities)
                {
                    assert(DspFormatFromWaveFormat(f.Format) != DspFormat::Unknown);

                    if (SUCCEEDED(m_device.audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &f.Format, nullptr)))
                    {
                        m_device.dspFormat = DspFormatFromWaveFormat(f.Format);
                        m_device.waveFormat = CopyWaveFormat(f.Format);
                        break;
                    }
                }
            }
            else
            {
                // Shared.
                m_device.dspFormat = DspFormat::Float;
                m_device.waveFormat = mixFormat;
            }

            ThrowIfFailed(m_device.audioClient->Initialize(m_device.exclusive ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
                                                           0, MILLISECONDS_TO_100NS_UNITS(m_device.bufferDuration),
                                                           0, &(*m_device.waveFormat), nullptr));

            ThrowIfFailed(m_device.audioClient->GetService(IID_PPV_ARGS(&m_device.audioRenderClient)));

            ThrowIfFailed(m_device.audioClient->GetService(IID_PPV_ARGS(&m_device.audioClock)));

            return 0;
        }
        catch (std::bad_alloc&)
        {
            ReleaseDevice();
            return 1;
        }
        catch (HRESULT)
        {
            ReleaseDevice();
            return 1;
        }
    }

    DWORD DeviceManager::ThreadProc()
    {
        CoInitializeHelper coInitializeHelper(COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

        HINSTANCE hInstance = GetModuleHandle(nullptr);

        WNDCLASSEX windowClass{sizeof(windowClass), 0, StaticWindowProc<DeviceManager>, 0, 0, hInstance,
                               NULL, NULL, NULL, nullptr, WindowClass, NULL};

        m_hWindow = NULL;
        if (coInitializeHelper.Initialized() && RegisterClassEx(&windowClass))
            m_hWindow = CreateWindowEx(0, WindowClass, WindowTitle, 0, 0, 0, 0, 0, 0, NULL, hInstance, this);

        if (m_hWindow != NULL)
        {
            m_windowInitialized.set_value(true);
            RunMessageLoop();
            ReleaseDevice();
        }
        else
        {
            m_windowInitialized.set_value(false);
        }

        return 0;
    }

    LRESULT DeviceManager::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch (msg)
        {
            case WM_DESTROY:
                if (m_queuedDestroy)
                    PostQuitMessage(0);
                return 0;

            case WM_CHECK_BITSTREAM_FORMAT:
                return OnCheckBitstreamFormat();

            case WM_CREATE_DEVICE:
                return OnCreateDevice();

            default:
                return DefWindowProc(hWnd, msg, wParam, lParam);
        }
    }
}
<commit_msg>Fall back to WAVE_FORMAT_PCM in exclusive mode<commit_after>#include "pch.h"
#include "DeviceManager.h"

#include "DspMatrix.h"

namespace SaneAudioRenderer
{
    namespace
    {
        const auto WindowClass = L"SaneAudioRenderer::DeviceManager";
        const auto WindowTitle = L"";

        enum
        {
            WM_CHECK_BITSTREAM_FORMAT = WM_USER + 100,
            WM_CREATE_DEVICE,
        };

        template <class T>
        bool IsLastInstance(T& smartPointer)
        {
            bool ret = (smartPointer.GetInterfacePtr()->AddRef() == 2);
            smartPointer.GetInterfacePtr()->Release();
            return ret;
        }

        WAVEFORMATEX BuildWaveFormat(WORD formatTag, uint32_t formatBits, uint32_t rate, uint32_t channelCount)
        {
            WAVEFORMATEX ret;

            ret.wFormatTag      = formatTag;
            ret.nChannels       = channelCount;
            ret.nSamplesPerSec  = rate;
            ret.nAvgBytesPerSec = formatBits / 8 * channelCount * rate;
            ret.nBlockAlign     = formatBits / 8 * channelCount;
            ret.wBitsPerSample  = formatBits;
            ret.cbSize          = (formatTag == WAVE_FORMAT_EXTENSIBLE) ? 22 : 0;

            return ret;
        }

        WAVEFORMATEXTENSIBLE BuildWaveFormatExt(GUID formatGuid, uint32_t formatBits, WORD formatExtProps,
                                                uint32_t rate, uint32_t channelCount, DWORD channelMask)
        {
            WAVEFORMATEXTENSIBLE ret;

            ret.Format                      = BuildWaveFormat(WAVE_FORMAT_EXTENSIBLE, formatBits, rate, channelCount);
            ret.Samples.wValidBitsPerSample = formatExtProps;
            ret.dwChannelMask               = channelMask;
            ret.SubFormat                   = formatGuid;

            return ret;
        }

        std::shared_ptr<std::wstring> GetDevicePropertyString(IPropertyStore* pStore, REFPROPERTYKEY key)
        {
            assert(pStore);

            PROPVARIANT prop;
            PropVariantInit(&prop);
            ThrowIfFailed(pStore->GetValue(key, &prop));
            auto ret = std::make_shared<std::wstring>(prop.pwszVal);
            PropVariantClear(&prop);

            return ret;
        }

        void CreateAudioClient(AudioDevice& output, ISettings* pSettings)
        {
            assert(pSettings);

            std::unique_ptr<wchar_t, CoTaskMemFreeDeleter> deviceName;

            {
                output.settingsSerial = pSettings->GetSerial();

                LPWSTR pDeviceName = nullptr;
                BOOL exclusive;
                ThrowIfFailed(pSettings->GetOuputDevice(&pDeviceName, &exclusive));

                deviceName.reset(pDeviceName);
                output.exclusive = !!exclusive;
            }

            IMMDeviceEnumeratorPtr enumerator;
            ThrowIfFailed(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr,
                                           CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&enumerator)));

            IMMDevicePtr device;
            IPropertyStorePtr devicePropertyStore;

            if (!deviceName || !*deviceName)
            {
                output.default = true;
                ThrowIfFailed(enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device));
                ThrowIfFailed(device->OpenPropertyStore(STGM_READ, &devicePropertyStore));
                output.friendlyName = GetDevicePropertyString(devicePropertyStore, PKEY_Device_FriendlyName);
            }
            else
            {
                output.default = false;

                IMMDeviceCollectionPtr collection;
                ThrowIfFailed(enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &collection));

                UINT count = 0;
                ThrowIfFailed(collection->GetCount(&count));

                for (UINT i = 0; i < count; i++)
                {
                    ThrowIfFailed(collection->Item(i, &device));
                    ThrowIfFailed(device->OpenPropertyStore(STGM_READ, &devicePropertyStore));
                    output.friendlyName = GetDevicePropertyString(devicePropertyStore, PKEY_Device_FriendlyName);

                    if (wcscmp(deviceName.get(), output.friendlyName->c_str()))
                    {
                        device = nullptr;
                        devicePropertyStore = nullptr;
                        output.friendlyName = nullptr;
                    }
                }
            }

            if (!device)
                return;

            output.adapterName = GetDevicePropertyString(devicePropertyStore, PKEY_DeviceInterface_FriendlyName);
            output.endpointName = GetDevicePropertyString(devicePropertyStore, PKEY_Device_DeviceDesc);

            ThrowIfFailed(device->Activate(__uuidof(IAudioClient),
                                           CLSCTX_INPROC_SERVER, nullptr, (void**)&output.audioClient));
        }
    }

    DeviceManager::DeviceManager(HRESULT& result)
    {
        if (FAILED(result))
            return;

        m_hThread = (HANDLE)_beginthreadex(nullptr, 0, StaticThreadProc<DeviceManager>, this, 0, nullptr);

        if (m_hThread == NULL || !m_windowInitialized.get_future().get())
            result = E_FAIL;
    }

    DeviceManager::~DeviceManager()
    {
        m_queuedDestroy = true;
        PostMessage(m_hWindow, WM_DESTROY, 0, 0);
        WaitForSingleObject(m_hThread, INFINITE);
        CloseHandle(m_hThread);
        UnregisterClass(WindowClass, GetModuleHandle(nullptr));
    }

    bool DeviceManager::BitstreamFormatSupported(SharedWaveFormat format, ISettings* pSettings)
    {
        assert(format);
        assert(pSettings);

        m_checkBitstreamFormat = format;
        m_checkBitstreamSettings = pSettings;
        m_queuedCheckBitstream = true;

        bool ret = (SendMessage(m_hWindow, WM_CHECK_BITSTREAM_FORMAT, 0, 0) == 0);

        m_checkBitstreamFormat = nullptr;
        m_checkBitstreamSettings = nullptr;
        assert(m_queuedCheckBitstream == false);

        return ret;
    }

    bool DeviceManager::CreateDevice(AudioDevice& device, SharedWaveFormat format, ISettings* pSettings)
    {
        assert(format);
        assert(pSettings);

        m_createDeviceFormat = format;
        m_createDeviceSettings = pSettings;
        m_queuedCreateDevice = true;

        bool ret = (SendMessage(m_hWindow, WM_CREATE_DEVICE, 0, 0) == 0);

        m_createDeviceFormat = nullptr;
        m_createDeviceSettings = nullptr;
        assert(m_queuedCreateDevice == false);

        device = m_device;

        return ret;
    }

    void DeviceManager::ReleaseDevice()
    {
        auto areLastInstances = [this]
        {
            if (m_device.audioClock && !IsLastInstance(m_device.audioClock))
                return false;

            m_device.audioClock = nullptr;

            if (m_device.audioRenderClient && !IsLastInstance(m_device.audioRenderClient))
                return false;

            m_device.audioRenderClient = nullptr;

            if (m_device.audioClient && !IsLastInstance(m_device.audioClient))
                return false;

            return true;
        };
        assert(areLastInstances());

        m_device = {};
    }

    LRESULT DeviceManager::OnCheckBitstreamFormat()
    {
        if (!m_queuedCheckBitstream)
            return 1;

        assert(m_checkBitstreamFormat);
        assert(m_checkBitstreamSettings);
        m_queuedCheckBitstream = false;

        try
        {
            AudioDevice device = {};

            CreateAudioClient(device, m_checkBitstreamSettings);

            if (!m_device.audioClient)
                return 1;

            return SUCCEEDED(m_device.audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,
                                                                     &(*m_checkBitstreamFormat), nullptr)) ? 0 : 1;
        }
        catch (HRESULT)
        {
            return 1;
        }
    }

    LRESULT DeviceManager::OnCreateDevice()
    {
        if (!m_queuedCreateDevice)
            return 1;

        assert(m_createDeviceFormat);
        assert(m_createDeviceSettings);
        m_queuedCreateDevice = false;

        ReleaseDevice();
        try
        {
            CreateAudioClient(m_device, m_createDeviceSettings);

            if (!m_device.audioClient)
                return 1;

            WAVEFORMATEX* pFormat;
            ThrowIfFailed(m_device.audioClient->GetMixFormat(&pFormat));
            SharedWaveFormat mixFormat(pFormat, CoTaskMemFreeDeleter());

            m_device.bufferDuration = 200;

            if (DspFormatFromWaveFormat(*m_createDeviceFormat) == DspFormat::Unknown)
            {
                // Exclusive bitstreaming.
                if (!m_device.exclusive)
                    return 1;

                m_device.dspFormat = DspFormat::Unknown;
                m_device.waveFormat = m_createDeviceFormat;
            }
            else if (m_device.exclusive)
            {
                // Exclusive.
                auto inputRate = m_createDeviceFormat->nSamplesPerSec;
                auto mixRate = mixFormat->nSamplesPerSec;
                auto mixChannels = mixFormat->nChannels;
                auto mixMask = DspMatrix::GetChannelMask(*mixFormat);

                auto priorities = make_array(
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32, 32, inputRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        32, 32, inputRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        24, 24, inputRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        32, 24, inputRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        16, 16, inputRate, mixChannels, mixMask),

                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32, 32, mixRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        32, 32, mixRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        24, 24, mixRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        32, 24, mixRate, mixChannels, mixMask),
                    BuildWaveFormatExt(KSDATAFORMAT_SUBTYPE_PCM,        16, 16, mixRate, mixChannels, mixMask),

                    WAVEFORMATEXTENSIBLE{BuildWaveFormat(WAVE_FORMAT_PCM, 16, inputRate, mixChannels)},
                    WAVEFORMATEXTENSIBLE{BuildWaveFormat(WAVE_FORMAT_PCM, 16, mixRate,   mixChannels)}
                );

                for (const auto& f : priorities)
                {
                    assert(DspFormatFromWaveFormat(f.Format) != DspFormat::Unknown);

                    if (SUCCEEDED(m_device.audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &f.Format, nullptr)))
                    {
                        m_device.dspFormat = DspFormatFromWaveFormat(f.Format);
                        m_device.waveFormat = CopyWaveFormat(f.Format);
                        break;
                    }
                }
            }
            else
            {
                // Shared.
                m_device.dspFormat = DspFormat::Float;
                m_device.waveFormat = mixFormat;
            }

            ThrowIfFailed(m_device.audioClient->Initialize(m_device.exclusive ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
                                                           0, MILLISECONDS_TO_100NS_UNITS(m_device.bufferDuration),
                                                           0, &(*m_device.waveFormat), nullptr));

            ThrowIfFailed(m_device.audioClient->GetService(IID_PPV_ARGS(&m_device.audioRenderClient)));

            ThrowIfFailed(m_device.audioClient->GetService(IID_PPV_ARGS(&m_device.audioClock)));

            return 0;
        }
        catch (std::bad_alloc&)
        {
            ReleaseDevice();
            return 1;
        }
        catch (HRESULT)
        {
            ReleaseDevice();
            return 1;
        }
    }

    DWORD DeviceManager::ThreadProc()
    {
        CoInitializeHelper coInitializeHelper(COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

        HINSTANCE hInstance = GetModuleHandle(nullptr);

        WNDCLASSEX windowClass{sizeof(windowClass), 0, StaticWindowProc<DeviceManager>, 0, 0, hInstance,
                               NULL, NULL, NULL, nullptr, WindowClass, NULL};

        m_hWindow = NULL;
        if (coInitializeHelper.Initialized() && RegisterClassEx(&windowClass))
            m_hWindow = CreateWindowEx(0, WindowClass, WindowTitle, 0, 0, 0, 0, 0, 0, NULL, hInstance, this);

        if (m_hWindow != NULL)
        {
            m_windowInitialized.set_value(true);
            RunMessageLoop();
            ReleaseDevice();
        }
        else
        {
            m_windowInitialized.set_value(false);
        }

        return 0;
    }

    LRESULT DeviceManager::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch (msg)
        {
            case WM_DESTROY:
                if (m_queuedDestroy)
                    PostQuitMessage(0);
                return 0;

            case WM_CHECK_BITSTREAM_FORMAT:
                return OnCheckBitstreamFormat();

            case WM_CREATE_DEVICE:
                return OnCreateDevice();

            default:
                return DefWindowProc(hWnd, msg, wParam, lParam);
        }
    }
}
<|endoftext|>


<commit_before>#ifndef FMO_EXPLORER_HPP
#define FMO_EXPLORER_HPP

#include <fmo/image.hpp>
#include <fmo/pointset.hpp>
#include <memory>

namespace fmo {
    /// Class for determining the presence of fast moving objects by analyzing a stream of images.
    struct Explorer {
        /// Configuration settings used by the constructor.
        struct Config {
            /// This value must be changed to match the input image size.
            Dims dims = {0, 0};
            /// Objects will be ignored unless they are at a distance from other objects in the
            /// image. This value is relative to image height.
            float minGap = 0.10;
            /// Maximum image height for processing. The input image will be downscaled by a factor
            /// of 2 until its height is less or equal to the specified value.
            int maxHeight = 300;
            /// Minimum image height for processing. The input image will be downscaled as long as
            /// its height is greater or equal to this value.
            int minHeight = 30;
            /// Minimum distance that an object must travel in a single frame. This value is
            /// relative to the length of the path travelled in three frames.
            float minMotion = 0.25;
        };

        Explorer(const Explorer&) = delete;
        Explorer& operator=(const Explorer&) = delete;

        ~Explorer();
        Explorer(const Config& cfg);
        Explorer(Explorer&&);
        Explorer& operator=(Explorer&&);

        /// Called every frame, providing the next image for processing. The processing will take
        /// place during the call and might take some time. The input is received by swapping the
        /// contents of the provided input image with an internal buffer.
        void setInputSwap(Image& input);

        /// Visualizes the result of detection, returning an image that should be displayed to the
        /// user.
        const Image& getDebugImage();

        /// A rectangular area.
        struct Bounds {
            Pos min; ///< minimum coordinates of the box that encloses the object
            Pos max; ///< maximum coordinates of the box that encloses the object
        };

        /// Information about a fast-moving object.
        struct Object {
            Bounds bounds;   ///< location in the input image
            PointSet points; ///< point locations
            Image diff1;     ///< difference image of this frame and the previous (cropped)
            Image diff2;     ///< difference image of the previous frame (cropped)
            Image diffAnd;   ///< intersection of differences (cropped)
        };

        /// Determines whether a new object has been found as a result of analyzing the last frame.
        bool haveObject() const;

        /// Provides information about the object that has been just found. Use haveObject() to
        /// check whether it makes sense to call this method.
        void getObject(Object& out) const;

    private:
        struct Impl;
        std::unique_ptr<Impl> mImpl; ///< implementation details of class Explorer
    };
}

#endif // FMO_EXPLORER_HPP
<commit_msg>Remove minHeight parameter<commit_after>#ifndef FMO_EXPLORER_HPP
#define FMO_EXPLORER_HPP

#include <fmo/image.hpp>
#include <fmo/pointset.hpp>
#include <memory>

namespace fmo {
    /// Class for determining the presence of fast moving objects by analyzing a stream of images.
    struct Explorer {
        /// Configuration settings used by the constructor.
        struct Config {
            /// This value must be changed to match the input image size.
            Dims dims = {0, 0};
            /// Objects will be ignored unless they are at a distance from other objects in the
            /// image. This value is relative to image height.
            float minGap = 0.10;
            /// Maximum image height for processing. The input image will be downscaled by a factor
            /// of 2 until its height is less or equal to the specified value.
            int maxHeight = 300;
            /// Minimum distance that an object must travel in a single frame. This value is
            /// relative to the length of the path travelled in three frames.
            float minMotion = 0.25;
        };

        Explorer(const Explorer&) = delete;
        Explorer& operator=(const Explorer&) = delete;

        ~Explorer();
        Explorer(const Config& cfg);
        Explorer(Explorer&&);
        Explorer& operator=(Explorer&&);

        /// Called every frame, providing the next image for processing. The processing will take
        /// place during the call and might take some time. The input is received by swapping the
        /// contents of the provided input image with an internal buffer.
        void setInputSwap(Image& input);

        /// Visualizes the result of detection, returning an image that should be displayed to the
        /// user.
        const Image& getDebugImage();

        /// A rectangular area.
        struct Bounds {
            Pos min; ///< minimum coordinates of the box that encloses the object
            Pos max; ///< maximum coordinates of the box that encloses the object
        };

        /// Information about a fast-moving object.
        struct Object {
            Bounds bounds;   ///< location in the input image
            PointSet points; ///< point locations
            Image diff1;     ///< difference image of this frame and the previous (cropped)
            Image diff2;     ///< difference image of the previous frame (cropped)
            Image diffAnd;   ///< intersection of differences (cropped)
        };

        /// Determines whether a new object has been found as a result of analyzing the last frame.
        bool haveObject() const;

        /// Provides information about the object that has been just found. Use haveObject() to
        /// check whether it makes sense to call this method.
        void getObject(Object& out) const;

    private:
        struct Impl;
        std::unique_ptr<Impl> mImpl; ///< implementation details of class Explorer
    };
}

#endif // FMO_EXPLORER_HPP
<|endoftext|>


<commit_before>#include <rtos.h>
#include <RPCVariable.h>

#include <Console.hpp>
#include <logger.hpp>
#include <assert.hpp>

#include "robot-devices.hpp"
#include "task-signals.hpp"
#include "motors.hpp"
#include "fpga.hpp"
#include "mpu-6050.hpp"
#include "io-expander.hpp"
#include "Pid.hpp"

const float kpi = 3.14159265358979f;

// Keep this pretty high for now. Ideally, drop it down to ~3 for production
// builds. Hopefully that'll be possible without the console
static const int CONTROL_LOOP_WAIT_MS = 5;

// Declaration for an alternative control loop thread for when the accel/gyro
// can't be used for whatever reason
void Task_Controller_Sensorless(const osThreadId mainThreadId);

namespace {
// The gyro/accel values are given RPC read/write access here
float gyroVals[3] = {0};
float accelVals[3] = {0};

// RPCVariable<float> gyrox(&gyroVals[0], "gyro-x");
// RPCVariable<float> gyroy(&gyroVals[1], "gyro-y");
// RPCVariable<float> gyroz(&gyroVals[2], "gyro-z");
// RPCVariable<float> accelx(&accelVals[0], "accel-x");
// RPCVariable<float> accely(&accelVals[1], "accel-y");
// RPCVariable<float> accelz(&accelVals[2], "accel-z");

// Making a temporary variable to test out the writing side of RPC variables
// int testVar;
// RPCVariable<int> test_var(&testVar, "var1");
}

/**
 * initializes the motion controller thread
 */
void Task_Controller(void const* args) {
    const osThreadId mainID = (const osThreadId)args;

    // Store the thread's ID
    osThreadId threadID = Thread::gettid();
    ASSERT(threadID != nullptr);

    // Store our priority so we know what to reset it to after running a command
    osPriority threadPriority = osThreadGetPriority(threadID);

    MPU6050 imu(RJ_I2C_SDA, RJ_I2C_SCL);

    imu.setBW(MPU6050_BW_256);
    imu.setGyroRange(MPU6050_GYRO_RANGE_250);
    imu.setAcceleroRange(MPU6050_ACCELERO_RANGE_2G);
    imu.setSleepMode(false);

    char testResp;
    if ((testResp = imu.testConnection())) {
        float resultRatio[6];
        imu.selfTest(resultRatio);
        LOG(INIT,
            "IMU self test results:\r\n"
            "    Accel (X,Y,Z):\t(%2.2f%%, %2.2f%%, %2.2f%%)\r\n"
            "    Gyro  (X,Y,Z):\t(%2.2f%%, %2.2f%%, %2.2f%%)",
            resultRatio[0], resultRatio[1], resultRatio[2], resultRatio[3],
            resultRatio[4], resultRatio[5]);

        LOG(INIT, "Control loop ready!\r\n    Thread ID: %u, Priority: %d",
            ((P_TCB)threadID)->task_id, threadPriority);
    } else {
        LOG(SEVERE,
            "MPU6050 not found!\t(response: 0x%02X)\r\n    Falling back to "
            "sensorless control loop.",
            testResp);

        // Start a thread that can function without the IMU, terminate us if it
        // ever returns
        Task_Controller_Sensorless(mainID);

        return;
    }

    // signal back to main and wait until we're signaled to continue
    osSignalSet(mainID, MAIN_TASK_CONTINUE);
    Thread::signal_wait(SUB_TASK_CONTINUE, osWaitForever);

    const uint16_t ENC_TICKS_PER_TURN = 2048;

    Pid motor2pid(0.0, 0.0, 0.0);

    std::vector<uint16_t> duty_cycles;

    const uint16_t kduty_cycle = 400;
    duty_cycles.assign(5, kduty_cycle);

    size_t ii = 0;
    bool spin_rev = true;

    uint16_t duty_cycle_all = kduty_cycle;

    while (true) {
        imu.getGyro(gyroVals);
        imu.getAccelero(accelVals);

        std::vector<uint16_t> enc_deltas(5);

        FPGA::Instance->set_duty_get_enc(duty_cycles.data(), duty_cycles.size(),
                                         enc_deltas.data(),
                                         enc_deltas.capacity());

        /*
         * The time since the last update is derived with the value of
         * WATCHDOG_TIMER_CLK_WIDTH in robocup.v
         *
         * The last encoder reading (5th one) from the FPGA is the watchdog
         * timer's tick since the last SPI transfer.
         *
         * Multiply the received tick count by:
         *     (1/18.432) * 2 * (2^WATCHDOG_TIMER_CLK_WIDTH)
         *
         * This will give you the duration since the last SPI transfer in
         * microseconds (us).
         *
         * For example, if WATCHDOG_TIMER_CLK_WIDTH = 6, here's how you would
         * convert into time assuming the fpga returned a reading of 1265 ticks:
         *     time_in_us = [ 1265 * (1/18.432) * 2 * (2^6) ] = 8784.7us
         *
         * The precision would be in increments of the multiplier. For
         * this example, that is:
         *     time_precision = 6.94us
         *
         */
        const float kdt = enc_deltas.back() * (1 / 18.432e6) * 2 * 64;

        // the target rev/s
        const float ktarget_rps = 5;

        // angular velocity of motor 3 in rad/s
        const float kvel = 2 * kpi * (enc_deltas[2] / ENC_TICKS_PER_TURN) / kdt;

        const float ktarget_vel = (2 * kpi) * ktarget_rps;

        // @125 duty cycle, 1260rpm @ no load
        TODO(remeasure the duty cycle and rad/s relationship of the motor)
        const float kmultiplier = 125.0f / (1260.0f * 2 * kpi / 60);

        const float vel_err = ktarget_vel - kvel;

        uint16_t dc = ktarget_vel * kmultiplier + motor2pid.run(vel_err);

        // duty cycle values range: 0 -> 511, the 9th bit is direction
        dc = std::min(dc, static_cast<uint16_t>(511));

        ii++;
        // if (ii < 20) {
        //     duty_cycle_all = kduty_cycle;
        // } else {
        //     duty_cycle_all = 0;
        //     spin_rev = !spin_rev;
        //     ii = 0;
        // }

        // if ((ii % 100) == 0) printf("dc: %u, dt: %f\r\n", dc, kdt);

        // set the direction
        duty_cycle_all |= (spin_rev << 9);

        std::fill(duty_cycles.begin(), duty_cycles.end(), duty_cycle_all);

        Thread::wait(CONTROL_LOOP_WAIT_MS);
    }
}

void Task_Controller_Sensorless(const osThreadId mainID) {
    // Store the thread's ID
    osThreadId threadID = Thread::gettid();
    ASSERT(threadID != nullptr);

    // Store our priority so we know what to reset it to after running a command
    osPriority threadPriority = osThreadGetPriority(threadID);

    LOG(INIT,
        "Sensorless control loop ready!\r\n    Thread ID: %u, Priority: %d",
        ((P_TCB)threadID)->task_id, threadPriority);

    // signal back to main and wait until we're signaled to continue
    osSignalSet(mainID, MAIN_TASK_CONTINUE);
    Thread::signal_wait(SUB_TASK_CONTINUE, osWaitForever);

    while (true) {
        Thread::wait(CONTROL_LOOP_WAIT_MS);
        Thread::yield();
    }
}
<commit_msg>make pretty<commit_after>#include <rtos.h>
#include <RPCVariable.h>

#include <Console.hpp>
#include <logger.hpp>
#include <assert.hpp>

#include "robot-devices.hpp"
#include "task-signals.hpp"
#include "motors.hpp"
#include "fpga.hpp"
#include "mpu-6050.hpp"
#include "io-expander.hpp"
#include "Pid.hpp"

const float kpi = 3.14159265358979f;

// Keep this pretty high for now. Ideally, drop it down to ~3 for production
// builds. Hopefully that'll be possible without the console
static const int CONTROL_LOOP_WAIT_MS = 5;

// Declaration for an alternative control loop thread for when the accel/gyro
// can't be used for whatever reason
void Task_Controller_Sensorless(const osThreadId mainThreadId);

namespace {
// The gyro/accel values are given RPC read/write access here
float gyroVals[3] = {0};
float accelVals[3] = {0};

// RPCVariable<float> gyrox(&gyroVals[0], "gyro-x");
// RPCVariable<float> gyroy(&gyroVals[1], "gyro-y");
// RPCVariable<float> gyroz(&gyroVals[2], "gyro-z");
// RPCVariable<float> accelx(&accelVals[0], "accel-x");
// RPCVariable<float> accely(&accelVals[1], "accel-y");
// RPCVariable<float> accelz(&accelVals[2], "accel-z");

// Making a temporary variable to test out the writing side of RPC variables
// int testVar;
// RPCVariable<int> test_var(&testVar, "var1");
}

/**
 * initializes the motion controller thread
 */
void Task_Controller(void const* args) {
    const osThreadId mainID = (const osThreadId)args;

    // Store the thread's ID
    osThreadId threadID = Thread::gettid();
    ASSERT(threadID != nullptr);

    // Store our priority so we know what to reset it to after running a command
    osPriority threadPriority = osThreadGetPriority(threadID);

    MPU6050 imu(RJ_I2C_SDA, RJ_I2C_SCL);

    imu.setBW(MPU6050_BW_256);
    imu.setGyroRange(MPU6050_GYRO_RANGE_250);
    imu.setAcceleroRange(MPU6050_ACCELERO_RANGE_2G);
    imu.setSleepMode(false);

    char testResp;
    if ((testResp = imu.testConnection())) {
        float resultRatio[6];
        imu.selfTest(resultRatio);
        LOG(INIT,
            "IMU self test results:\r\n"
            "    Accel (X,Y,Z):\t(%2.2f%%, %2.2f%%, %2.2f%%)\r\n"
            "    Gyro  (X,Y,Z):\t(%2.2f%%, %2.2f%%, %2.2f%%)",
            resultRatio[0], resultRatio[1], resultRatio[2], resultRatio[3],
            resultRatio[4], resultRatio[5]);

        LOG(INIT, "Control loop ready!\r\n    Thread ID: %u, Priority: %d",
            ((P_TCB)threadID)->task_id, threadPriority);
    } else {
        LOG(SEVERE,
            "MPU6050 not found!\t(response: 0x%02X)\r\n    Falling back to "
            "sensorless control loop.",
            testResp);

        // Start a thread that can function without the IMU, terminate us if it
        // ever returns
        Task_Controller_Sensorless(mainID);

        return;
    }

    // signal back to main and wait until we're signaled to continue
    osSignalSet(mainID, MAIN_TASK_CONTINUE);
    Thread::signal_wait(SUB_TASK_CONTINUE, osWaitForever);

    const uint16_t ENC_TICKS_PER_TURN = 2048;

    Pid motor2pid(0.0, 0.0, 0.0);

    std::vector<uint16_t> duty_cycles;

    const uint16_t kduty_cycle = 400;
    duty_cycles.assign(5, kduty_cycle);

    size_t ii = 0;
    bool spin_rev = true;

    uint16_t duty_cycle_all = kduty_cycle;

    while (true) {
        imu.getGyro(gyroVals);
        imu.getAccelero(accelVals);

        std::vector<uint16_t> enc_deltas(5);

        FPGA::Instance->set_duty_get_enc(duty_cycles.data(), duty_cycles.size(),
                                         enc_deltas.data(),
                                         enc_deltas.capacity());

        /*
         * The time since the last update is derived with the value of
         * WATCHDOG_TIMER_CLK_WIDTH in robocup.v
         *
         * The last encoder reading (5th one) from the FPGA is the watchdog
         * timer's tick since the last SPI transfer.
         *
         * Multiply the received tick count by:
         *     (1/18.432) * 2 * (2^WATCHDOG_TIMER_CLK_WIDTH)
         *
         * This will give you the duration since the last SPI transfer in
         * microseconds (us).
         *
         * For example, if WATCHDOG_TIMER_CLK_WIDTH = 6, here's how you would
         * convert into time assuming the fpga returned a reading of 1265 ticks:
         *     time_in_us = [ 1265 * (1/18.432) * 2 * (2^6) ] = 8784.7us
         *
         * The precision would be in increments of the multiplier. For
         * this example, that is:
         *     time_precision = 6.94us
         *
         */
        const float kdt = enc_deltas.back() * (1 / 18.432e6) * 2 * 64;

        // the target rev/s
        const float ktarget_rps = 5;

        // angular velocity of motor 3 in rad/s
        const float kvel = 2 * kpi * (enc_deltas[2] / ENC_TICKS_PER_TURN) / kdt;

        const float ktarget_vel = (2 * kpi) * ktarget_rps;

        // @125 duty cycle, 1260rpm @ no load
        TODO(remeasure the duty cycle and rad / s relationship of the motor)
        const float kmultiplier = 125.0f / (1260.0f * 2 * kpi / 60);

        const float vel_err = ktarget_vel - kvel;

        uint16_t dc = ktarget_vel * kmultiplier + motor2pid.run(vel_err);

        // duty cycle values range: 0 -> 511, the 9th bit is direction
        dc = std::min(dc, static_cast<uint16_t>(511));

        ii++;
        // if (ii < 20) {
        //     duty_cycle_all = kduty_cycle;
        // } else {
        //     duty_cycle_all = 0;
        //     spin_rev = !spin_rev;
        //     ii = 0;
        // }

        // if ((ii % 100) == 0) printf("dc: %u, dt: %f\r\n", dc, kdt);

        // set the direction
        duty_cycle_all |= (spin_rev << 9);

        std::fill(duty_cycles.begin(), duty_cycles.end(), duty_cycle_all);

        Thread::wait(CONTROL_LOOP_WAIT_MS);
    }
}

void Task_Controller_Sensorless(const osThreadId mainID) {
    // Store the thread's ID
    osThreadId threadID = Thread::gettid();
    ASSERT(threadID != nullptr);

    // Store our priority so we know what to reset it to after running a command
    osPriority threadPriority = osThreadGetPriority(threadID);

    LOG(INIT,
        "Sensorless control loop ready!\r\n    Thread ID: %u, Priority: %d",
        ((P_TCB)threadID)->task_id, threadPriority);

    // signal back to main and wait until we're signaled to continue
    osSignalSet(mainID, MAIN_TASK_CONTINUE);
    Thread::signal_wait(SUB_TASK_CONTINUE, osWaitForever);

    while (true) {
        Thread::wait(CONTROL_LOOP_WAIT_MS);
        Thread::yield();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 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 "ash/launcher/launcher.h"

#include <algorithm>
#include <cmath>

#include "ash/focus_cycler.h"
#include "ash/launcher/launcher_delegate.h"
#include "ash/launcher/launcher_model.h"
#include "ash/launcher/launcher_navigator.h"
#include "ash/launcher/launcher_view.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/shell_window_ids.h"
#include "ash/wm/shelf_layout_manager.h"
#include "ash/wm/window_properties.h"
#include "grit/ash_resources.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/views/accessible_pane_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"

namespace {
// Size of black border at bottom (or side) of launcher.
const int kNumBlackPixels = 3;
// Alpha to paint dimming image with.
const int kDimAlpha = 96;
}

namespace ash {

// The contents view of the Widget. This view contains LauncherView and
// sizes it to the width of the widget minus the size of the status area.
class Launcher::DelegateView : public views::WidgetDelegate,
                               public views::AccessiblePaneView,
                               public internal::BackgroundAnimatorDelegate {
 public:
  explicit DelegateView(Launcher* launcher);
  virtual ~DelegateView();

  void set_focus_cycler(internal::FocusCycler* focus_cycler) {
    focus_cycler_ = focus_cycler;
  }
  internal::FocusCycler* focus_cycler() {
    return focus_cycler_;
  }

  // views::View overrides
  virtual gfx::Size GetPreferredSize() OVERRIDE;
  virtual void Layout() OVERRIDE;
  virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE;

  // views::WidgetDelegateView overrides:
  virtual views::Widget* GetWidget() OVERRIDE {
    return View::GetWidget();
  }
  virtual const views::Widget* GetWidget() const OVERRIDE {
    return View::GetWidget();
  }
  virtual bool CanActivate() const OVERRIDE {
    // We don't want mouse clicks to activate us, but we need to allow
    // activation when the user is using the keyboard (FocusCycler).
    return focus_cycler_ && focus_cycler_->widget_activating() == GetWidget();
  }

  // BackgroundAnimatorDelegate overrides:
  virtual void UpdateBackground(int alpha) OVERRIDE;

 private:
  Launcher* launcher_;
  internal::FocusCycler* focus_cycler_;
  int alpha_;

  DISALLOW_COPY_AND_ASSIGN(DelegateView);
};

// Class used to slightly dim shelf items when maximized and visible. It also
// makes sure the widget changes size to always be of the same size as the
// shelf.
class DimmerView : public views::WidgetDelegateView,
                   public aura::WindowObserver {
 public:
  explicit DimmerView(views::Widget* launcher)
      : launcher_(launcher) {
    launcher_->GetNativeWindow()->AddObserver(this);
  }

  ~DimmerView() {
    if (launcher_)
      launcher_->GetNativeWindow()->RemoveObserver(this);
  }

 private:
  // views::View overrides:
  virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE {
    SkPaint paint;
    static const gfx::ImageSkia* launcher_background = NULL;
    if (!launcher_background) {
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      launcher_background =
          rb.GetImageNamed(IDR_AURA_LAUNCHER_DIMMING).ToImageSkia();
    }
    paint.setAlpha(kDimAlpha);
    canvas->DrawImageInt(
        *launcher_background,
        0, 0, launcher_background->width(), launcher_background->height(),
        0, 0, width(), height(),
        false,
        paint);
  }

  // aura::WindowObserver overrides:
  virtual void OnWindowBoundsChanged(aura::Window* window,
                                     const gfx::Rect& old_bounds,
                                     const gfx::Rect& new_bounds) OVERRIDE {
    CHECK_EQ(window, launcher_->GetNativeWindow());
    GetWidget()->GetNativeWindow()->SetBounds(window->bounds());
  }

  virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
    CHECK_EQ(window, launcher_->GetNativeWindow());
    launcher_->GetNativeWindow()->RemoveObserver(this);
    launcher_ = NULL;
  }

  views::Widget* launcher_;
  DISALLOW_COPY_AND_ASSIGN(DimmerView);
};

Launcher::DelegateView::DelegateView(Launcher* launcher)
    : launcher_(launcher),
      focus_cycler_(NULL),
      alpha_(0) {
}

Launcher::DelegateView::~DelegateView() {
}

gfx::Size Launcher::DelegateView::GetPreferredSize() {
  return child_count() > 0 ? child_at(0)->GetPreferredSize() : gfx::Size();
}

void Launcher::DelegateView::Layout() {
  if (child_count() == 0)
    return;
  View* launcher_view = child_at(0);

  if (launcher_->alignment_ == SHELF_ALIGNMENT_BOTTOM) {
    int w = std::max(0, width() - launcher_->status_size_.width());
    launcher_view->SetBounds(0, 0, w, height());
  } else {
    int h = std::max(0, height() - launcher_->status_size_.height());
    launcher_view->SetBounds(0, 0, width(), h);
  }
}

void Launcher::DelegateView::OnPaintBackground(gfx::Canvas* canvas) {
  if (launcher_->alignment_ == SHELF_ALIGNMENT_BOTTOM) {
    SkPaint paint;
    static const gfx::ImageSkia* launcher_background = NULL;
    if (!launcher_background) {
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      launcher_background =
          rb.GetImageNamed(IDR_AURA_LAUNCHER_BACKGROUND).ToImageSkia();
    }
    paint.setAlpha(alpha_);
    canvas->DrawImageInt(
        *launcher_background,
        0, 0, launcher_background->width(), launcher_background->height(),
        0, 0, width(), height(),
        false,
        paint);
    canvas->FillRect(
        gfx::Rect(0, height() - kNumBlackPixels, width(), kNumBlackPixels),
        SK_ColorBLACK);
  } else {
    // TODO(davemoore): when we get an image for the side launcher background
    // use it, and handle black border.
    canvas->DrawColor(SkColorSetARGB(alpha_, 0, 0, 0));
  }
}

void Launcher::DelegateView::UpdateBackground(int alpha) {
  alpha_ = alpha;
  SchedulePaint();
}

// Launcher --------------------------------------------------------------------

Launcher::Launcher(aura::Window* window_container,
                   internal::ShelfLayoutManager* shelf_layout_manager)
    : widget_(NULL),
      window_container_(window_container),
      delegate_view_(new DelegateView(this)),
      launcher_view_(NULL),
      alignment_(SHELF_ALIGNMENT_BOTTOM),
      background_animator_(delegate_view_, 0, kLauncherBackgroundAlpha) {
  model_.reset(new LauncherModel);
  if (Shell::GetInstance()->delegate()) {
    delegate_.reset(
        Shell::GetInstance()->delegate()->CreateLauncherDelegate(model_.get()));
  }

  widget_.reset(new views::Widget);
  views::Widget::InitParams params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  params.transparent = true;
  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  params.parent = Shell::GetContainer(
      window_container_->GetRootWindow(),
      ash::internal::kShellWindowId_LauncherContainer);
  launcher_view_ = new internal::LauncherView(
      model_.get(), delegate_.get(), shelf_layout_manager);
  launcher_view_->Init();
  delegate_view_->AddChildView(launcher_view_);
  params.delegate = delegate_view_;
  widget_->Init(params);
  widget_->GetNativeWindow()->SetName("LauncherWindow");
  gfx::Size pref =
      static_cast<views::View*>(launcher_view_)->GetPreferredSize();
  widget_->SetBounds(gfx::Rect(pref));
  // The launcher should not take focus when it is initially shown.
  widget_->set_focus_on_creation(false);
  widget_->SetContentsView(delegate_view_);
  widget_->GetNativeView()->SetName("LauncherView");
  widget_->GetNativeView()->SetProperty(internal::kStayInSameRootWindowKey,
                                        true);
}

Launcher::~Launcher() {
}

// static
Launcher* Launcher::ForPrimaryDisplay() {
  return internal::RootWindowController::ForLauncher(
      Shell::GetPrimaryRootWindow())->launcher();
}

// static
Launcher* Launcher::ForWindow(aura::Window* window) {
  return internal::RootWindowController::ForLauncher(window)->launcher();
}

void Launcher::SetFocusCycler(internal::FocusCycler* focus_cycler) {
  delegate_view_->set_focus_cycler(focus_cycler);
  if (focus_cycler)
    focus_cycler->AddWidget(widget_.get());
}

internal::FocusCycler* Launcher::GetFocusCycler() {
  return delegate_view_->focus_cycler();
}

void Launcher::SetAlignment(ShelfAlignment alignment) {
  alignment_ = alignment;
  launcher_view_->SetAlignment(alignment);
  // ShelfLayoutManager will resize the launcher.
}

void Launcher::SetPaintsBackground(
      bool value,
      internal::BackgroundAnimator::ChangeType change_type) {
  background_animator_.SetPaintsBackground(value, change_type);
}

void Launcher::SetDimsShelf(bool value) {
  if (value == (dimmer_.get() != NULL))
    return;

  if (!value) {
    dimmer_.reset();
    return;
  }

  dimmer_.reset(new views::Widget);
  views::Widget::InitParams params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  params.transparent = true;
  params.can_activate = false;
  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  params.parent = Shell::GetContainer(
      window_container_->GetRootWindow(),
      ash::internal::kShellWindowId_LauncherContainer);
  params.accept_events = false;
  dimmer_->Init(params);
  dimmer_->GetNativeWindow()->SetName("LauncherDimmer");
  dimmer_->SetBounds(widget_->GetWindowBoundsInScreen());
  // The launcher should not take focus when it is initially shown.
  dimmer_->set_focus_on_creation(false);
  dimmer_->SetContentsView(new DimmerView(widget_.get()));
  dimmer_->GetNativeView()->SetName("LauncherDimmerView");
  dimmer_->GetNativeView()->SetProperty(internal::kStayInSameRootWindowKey,
                                        true);
  dimmer_->Show();
}

bool Launcher::GetDimsShelf() const {
  return dimmer_.get() && dimmer_->IsVisible();
}

void Launcher::SetStatusSize(const gfx::Size& size) {
  if (status_size_ == size)
    return;

  status_size_ = size;
  delegate_view_->Layout();
}

gfx::Rect Launcher::GetScreenBoundsOfItemIconForWindow(aura::Window* window) {
  if (!delegate_.get())
    return gfx::Rect();

  LauncherID id = delegate_->GetIDByWindow(window);
  gfx::Rect bounds(launcher_view_->GetIdealBoundsOfItemIcon(id));
  if (bounds.IsEmpty())
    return bounds;

  gfx::Point screen_origin;
  views::View::ConvertPointToScreen(launcher_view_, &screen_origin);
  return gfx::Rect(screen_origin.x() + bounds.x(),
                   screen_origin.y() + bounds.y(),
                   bounds.width(),
                   bounds.height());
}

void Launcher::ActivateLauncherItem(int index) {
  DCHECK(delegate_.get());
  const ash::LauncherItems& items = model_->items();
  delegate_->ItemClicked(items[index], ui::EF_NONE);
}

void Launcher::CycleWindowLinear(CycleDirection direction) {
  int item_index = GetNextActivatedItemIndex(*model(), direction);
  if (item_index >= 0)
    ActivateLauncherItem(item_index);
}

void Launcher::AddIconObserver(LauncherIconObserver* observer) {
  launcher_view_->AddIconObserver(observer);
}

void Launcher::RemoveIconObserver(LauncherIconObserver* observer) {
  launcher_view_->RemoveIconObserver(observer);
}

bool Launcher::IsShowingMenu() const {
  return launcher_view_->IsShowingMenu();
}

void Launcher::ShowContextMenu(const gfx::Point& location) {
  launcher_view_->ShowContextMenu(location, false);
}

bool Launcher::IsShowingOverflowBubble() const {
  return launcher_view_->IsShowingOverflowBubble();
}

void Launcher::SetVisible(bool visible) const {
  delegate_view_->SetVisible(visible);
}

views::View* Launcher::GetAppListButtonView() const {
  return launcher_view_->GetAppListButtonView();
}

void Launcher::SetWidgetBounds(const gfx::Rect bounds) {
  widget_->SetBounds(bounds);
  if (dimmer_.get())
    dimmer_->SetBounds(bounds);
}

internal::LauncherView* Launcher::GetLauncherViewForTest() {
  return launcher_view_;
}

}  // namespace ash
<commit_msg>SetBounds() after setting kStayInSameRootWindowKey for the launcher.<commit_after>// Copyright (c) 2012 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 "ash/launcher/launcher.h"

#include <algorithm>
#include <cmath>

#include "ash/focus_cycler.h"
#include "ash/launcher/launcher_delegate.h"
#include "ash/launcher/launcher_model.h"
#include "ash/launcher/launcher_navigator.h"
#include "ash/launcher/launcher_view.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/shell_window_ids.h"
#include "ash/wm/shelf_layout_manager.h"
#include "ash/wm/window_properties.h"
#include "grit/ash_resources.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/views/accessible_pane_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"

namespace {
// Size of black border at bottom (or side) of launcher.
const int kNumBlackPixels = 3;
// Alpha to paint dimming image with.
const int kDimAlpha = 96;
}

namespace ash {

// The contents view of the Widget. This view contains LauncherView and
// sizes it to the width of the widget minus the size of the status area.
class Launcher::DelegateView : public views::WidgetDelegate,
                               public views::AccessiblePaneView,
                               public internal::BackgroundAnimatorDelegate {
 public:
  explicit DelegateView(Launcher* launcher);
  virtual ~DelegateView();

  void set_focus_cycler(internal::FocusCycler* focus_cycler) {
    focus_cycler_ = focus_cycler;
  }
  internal::FocusCycler* focus_cycler() {
    return focus_cycler_;
  }

  // views::View overrides
  virtual gfx::Size GetPreferredSize() OVERRIDE;
  virtual void Layout() OVERRIDE;
  virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE;

  // views::WidgetDelegateView overrides:
  virtual views::Widget* GetWidget() OVERRIDE {
    return View::GetWidget();
  }
  virtual const views::Widget* GetWidget() const OVERRIDE {
    return View::GetWidget();
  }
  virtual bool CanActivate() const OVERRIDE {
    // We don't want mouse clicks to activate us, but we need to allow
    // activation when the user is using the keyboard (FocusCycler).
    return focus_cycler_ && focus_cycler_->widget_activating() == GetWidget();
  }

  // BackgroundAnimatorDelegate overrides:
  virtual void UpdateBackground(int alpha) OVERRIDE;

 private:
  Launcher* launcher_;
  internal::FocusCycler* focus_cycler_;
  int alpha_;

  DISALLOW_COPY_AND_ASSIGN(DelegateView);
};

// Class used to slightly dim shelf items when maximized and visible. It also
// makes sure the widget changes size to always be of the same size as the
// shelf.
class DimmerView : public views::WidgetDelegateView,
                   public aura::WindowObserver {
 public:
  explicit DimmerView(views::Widget* launcher)
      : launcher_(launcher) {
    launcher_->GetNativeWindow()->AddObserver(this);
  }

  ~DimmerView() {
    if (launcher_)
      launcher_->GetNativeWindow()->RemoveObserver(this);
  }

 private:
  // views::View overrides:
  virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE {
    SkPaint paint;
    static const gfx::ImageSkia* launcher_background = NULL;
    if (!launcher_background) {
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      launcher_background =
          rb.GetImageNamed(IDR_AURA_LAUNCHER_DIMMING).ToImageSkia();
    }
    paint.setAlpha(kDimAlpha);
    canvas->DrawImageInt(
        *launcher_background,
        0, 0, launcher_background->width(), launcher_background->height(),
        0, 0, width(), height(),
        false,
        paint);
  }

  // aura::WindowObserver overrides:
  virtual void OnWindowBoundsChanged(aura::Window* window,
                                     const gfx::Rect& old_bounds,
                                     const gfx::Rect& new_bounds) OVERRIDE {
    CHECK_EQ(window, launcher_->GetNativeWindow());
    GetWidget()->GetNativeWindow()->SetBounds(window->bounds());
  }

  virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
    CHECK_EQ(window, launcher_->GetNativeWindow());
    launcher_->GetNativeWindow()->RemoveObserver(this);
    launcher_ = NULL;
  }

  views::Widget* launcher_;
  DISALLOW_COPY_AND_ASSIGN(DimmerView);
};

Launcher::DelegateView::DelegateView(Launcher* launcher)
    : launcher_(launcher),
      focus_cycler_(NULL),
      alpha_(0) {
}

Launcher::DelegateView::~DelegateView() {
}

gfx::Size Launcher::DelegateView::GetPreferredSize() {
  return child_count() > 0 ? child_at(0)->GetPreferredSize() : gfx::Size();
}

void Launcher::DelegateView::Layout() {
  if (child_count() == 0)
    return;
  View* launcher_view = child_at(0);

  if (launcher_->alignment_ == SHELF_ALIGNMENT_BOTTOM) {
    int w = std::max(0, width() - launcher_->status_size_.width());
    launcher_view->SetBounds(0, 0, w, height());
  } else {
    int h = std::max(0, height() - launcher_->status_size_.height());
    launcher_view->SetBounds(0, 0, width(), h);
  }
}

void Launcher::DelegateView::OnPaintBackground(gfx::Canvas* canvas) {
  if (launcher_->alignment_ == SHELF_ALIGNMENT_BOTTOM) {
    SkPaint paint;
    static const gfx::ImageSkia* launcher_background = NULL;
    if (!launcher_background) {
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      launcher_background =
          rb.GetImageNamed(IDR_AURA_LAUNCHER_BACKGROUND).ToImageSkia();
    }
    paint.setAlpha(alpha_);
    canvas->DrawImageInt(
        *launcher_background,
        0, 0, launcher_background->width(), launcher_background->height(),
        0, 0, width(), height(),
        false,
        paint);
    canvas->FillRect(
        gfx::Rect(0, height() - kNumBlackPixels, width(), kNumBlackPixels),
        SK_ColorBLACK);
  } else {
    // TODO(davemoore): when we get an image for the side launcher background
    // use it, and handle black border.
    canvas->DrawColor(SkColorSetARGB(alpha_, 0, 0, 0));
  }
}

void Launcher::DelegateView::UpdateBackground(int alpha) {
  alpha_ = alpha;
  SchedulePaint();
}

// Launcher --------------------------------------------------------------------

Launcher::Launcher(aura::Window* window_container,
                   internal::ShelfLayoutManager* shelf_layout_manager)
    : widget_(NULL),
      window_container_(window_container),
      delegate_view_(new DelegateView(this)),
      launcher_view_(NULL),
      alignment_(SHELF_ALIGNMENT_BOTTOM),
      background_animator_(delegate_view_, 0, kLauncherBackgroundAlpha) {
  model_.reset(new LauncherModel);
  if (Shell::GetInstance()->delegate()) {
    delegate_.reset(
        Shell::GetInstance()->delegate()->CreateLauncherDelegate(model_.get()));
  }

  widget_.reset(new views::Widget);
  views::Widget::InitParams params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  params.transparent = true;
  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  params.parent = Shell::GetContainer(
      window_container_->GetRootWindow(),
      ash::internal::kShellWindowId_LauncherContainer);
  launcher_view_ = new internal::LauncherView(
      model_.get(), delegate_.get(), shelf_layout_manager);
  launcher_view_->Init();
  delegate_view_->AddChildView(launcher_view_);
  params.delegate = delegate_view_;
  widget_->Init(params);
  widget_->GetNativeWindow()->SetName("LauncherWindow");
  // The launcher should not take focus when it is initially shown.
  widget_->set_focus_on_creation(false);
  widget_->SetContentsView(delegate_view_);
  widget_->GetNativeView()->SetName("LauncherView");
  widget_->GetNativeView()->SetProperty(internal::kStayInSameRootWindowKey,
                                        true);
  // SetBounds() has to be called after kStayInSameRootWindowKey is set.
  gfx::Size pref =
      static_cast<views::View*>(launcher_view_)->GetPreferredSize();
  widget_->SetBounds(gfx::Rect(pref));
}

Launcher::~Launcher() {
}

// static
Launcher* Launcher::ForPrimaryDisplay() {
  return internal::RootWindowController::ForLauncher(
      Shell::GetPrimaryRootWindow())->launcher();
}

// static
Launcher* Launcher::ForWindow(aura::Window* window) {
  return internal::RootWindowController::ForLauncher(window)->launcher();
}

void Launcher::SetFocusCycler(internal::FocusCycler* focus_cycler) {
  delegate_view_->set_focus_cycler(focus_cycler);
  if (focus_cycler)
    focus_cycler->AddWidget(widget_.get());
}

internal::FocusCycler* Launcher::GetFocusCycler() {
  return delegate_view_->focus_cycler();
}

void Launcher::SetAlignment(ShelfAlignment alignment) {
  alignment_ = alignment;
  launcher_view_->SetAlignment(alignment);
  // ShelfLayoutManager will resize the launcher.
}

void Launcher::SetPaintsBackground(
      bool value,
      internal::BackgroundAnimator::ChangeType change_type) {
  background_animator_.SetPaintsBackground(value, change_type);
}

void Launcher::SetDimsShelf(bool value) {
  if (value == (dimmer_.get() != NULL))
    return;

  if (!value) {
    dimmer_.reset();
    return;
  }

  dimmer_.reset(new views::Widget);
  views::Widget::InitParams params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  params.transparent = true;
  params.can_activate = false;
  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  params.parent = Shell::GetContainer(
      window_container_->GetRootWindow(),
      ash::internal::kShellWindowId_LauncherContainer);
  params.accept_events = false;
  dimmer_->Init(params);
  dimmer_->GetNativeWindow()->SetName("LauncherDimmer");
  dimmer_->SetBounds(widget_->GetWindowBoundsInScreen());
  // The launcher should not take focus when it is initially shown.
  dimmer_->set_focus_on_creation(false);
  dimmer_->SetContentsView(new DimmerView(widget_.get()));
  dimmer_->GetNativeView()->SetName("LauncherDimmerView");
  dimmer_->GetNativeView()->SetProperty(internal::kStayInSameRootWindowKey,
                                        true);
  dimmer_->Show();
}

bool Launcher::GetDimsShelf() const {
  return dimmer_.get() && dimmer_->IsVisible();
}

void Launcher::SetStatusSize(const gfx::Size& size) {
  if (status_size_ == size)
    return;

  status_size_ = size;
  delegate_view_->Layout();
}

gfx::Rect Launcher::GetScreenBoundsOfItemIconForWindow(aura::Window* window) {
  if (!delegate_.get())
    return gfx::Rect();

  LauncherID id = delegate_->GetIDByWindow(window);
  gfx::Rect bounds(launcher_view_->GetIdealBoundsOfItemIcon(id));
  if (bounds.IsEmpty())
    return bounds;

  gfx::Point screen_origin;
  views::View::ConvertPointToScreen(launcher_view_, &screen_origin);
  return gfx::Rect(screen_origin.x() + bounds.x(),
                   screen_origin.y() + bounds.y(),
                   bounds.width(),
                   bounds.height());
}

void Launcher::ActivateLauncherItem(int index) {
  DCHECK(delegate_.get());
  const ash::LauncherItems& items = model_->items();
  delegate_->ItemClicked(items[index], ui::EF_NONE);
}

void Launcher::CycleWindowLinear(CycleDirection direction) {
  int item_index = GetNextActivatedItemIndex(*model(), direction);
  if (item_index >= 0)
    ActivateLauncherItem(item_index);
}

void Launcher::AddIconObserver(LauncherIconObserver* observer) {
  launcher_view_->AddIconObserver(observer);
}

void Launcher::RemoveIconObserver(LauncherIconObserver* observer) {
  launcher_view_->RemoveIconObserver(observer);
}

bool Launcher::IsShowingMenu() const {
  return launcher_view_->IsShowingMenu();
}

void Launcher::ShowContextMenu(const gfx::Point& location) {
  launcher_view_->ShowContextMenu(location, false);
}

bool Launcher::IsShowingOverflowBubble() const {
  return launcher_view_->IsShowingOverflowBubble();
}

void Launcher::SetVisible(bool visible) const {
  delegate_view_->SetVisible(visible);
}

views::View* Launcher::GetAppListButtonView() const {
  return launcher_view_->GetAppListButtonView();
}

void Launcher::SetWidgetBounds(const gfx::Rect bounds) {
  widget_->SetBounds(bounds);
  if (dimmer_.get())
    dimmer_->SetBounds(bounds);
}

internal::LauncherView* Launcher::GetLauncherViewForTest() {
  return launcher_view_;
}

}  // namespace ash
<|endoftext|>


<commit_before>//==- Deserialize.cpp - Generic Object Serialization to Bitcode --*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the internal methods used for object serialization.
//
//===----------------------------------------------------------------------===//

#include "llvm/Bitcode/Deserialize.h"

#ifdef DEBUG_BACKPATCH
#include "llvm/Support/Streams.h"
#endif

using namespace llvm;

Deserializer::Deserializer(BitstreamReader& stream)
  : Stream(stream), RecIdx(0), FreeList(NULL), AbbrevNo(0), RecordCode(0) {

    StreamStart = Stream.GetCurrentBitNo();
}

Deserializer::~Deserializer() {
  assert (RecIdx >= Record.size() &&
          "Still scanning bitcode record when deserialization completed.");

#ifdef DEBUG_BACKPATCH
  for (MapTy::iterator I=BPatchMap.begin(), E=BPatchMap.end(); I!=E; ++I)
    assert (I->first.hasFinalPtr() &&
            "Some pointers were not backpatched.");
#endif
}

bool Deserializer::inRecord() {
  if (Record.size() > 0) {
    if (RecIdx >= Record.size()) {
      RecIdx = 0;
      Record.clear();
      AbbrevNo = 0;
      return false;
    }
    else
      return true;
  }

  return false;
}

bool Deserializer::AdvanceStream() {
  assert (!inRecord() &&
          "Cannot advance stream.  Still processing a record.");

  if (AbbrevNo == bitc::ENTER_SUBBLOCK ||
      AbbrevNo >= bitc::UNABBREV_RECORD)
    return true;

  while (!Stream.AtEndOfStream()) {

    uint64_t Pos = Stream.GetCurrentBitNo();
    AbbrevNo = Stream.ReadCode();

    switch (AbbrevNo) {
      case bitc::ENTER_SUBBLOCK: {
        unsigned id = Stream.ReadSubBlockID();

        // Determine the extent of the block.  This is useful for jumping around
        // the stream.  This is hack: we read the header of the block, save
        // the length, and then revert the bitstream to a location just before
        // the block is entered.
        uint64_t BPos = Stream.GetCurrentBitNo();
        Stream.ReadVBR(bitc::CodeLenWidth); // Skip the code size.
        Stream.SkipToWord();
        unsigned NumWords = Stream.Read(bitc::BlockSizeWidth);
        Stream.JumpToBit(BPos);

        BlockStack.push_back(Location(Pos,id,NumWords));
        break;
      }

      case bitc::END_BLOCK: {
        bool x = Stream.ReadBlockEnd();
        assert(!x && "Error at block end."); x=x;
        BlockStack.pop_back();
        continue;
      }

      case bitc::DEFINE_ABBREV:
        Stream.ReadAbbrevRecord();
        continue;

      default:
        break;
    }

    return true;
  }

  return false;
}

void Deserializer::ReadRecord() {

  while (AdvanceStream() && AbbrevNo == bitc::ENTER_SUBBLOCK) {
    assert (!BlockStack.empty());
    Stream.EnterSubBlock(BlockStack.back().BlockID);
    AbbrevNo = 0;
  }

  if (Stream.AtEndOfStream())
    return;

  assert (Record.empty());
  assert (AbbrevNo >= bitc::UNABBREV_RECORD);
  RecordCode = Stream.ReadRecord(AbbrevNo,Record);
  assert (Record.size() > 0);
}

void Deserializer::SkipBlock() {
  assert (!inRecord());

  if (AtEnd())
    return;

  AdvanceStream();

  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
  BlockStack.pop_back();
  Stream.SkipBlock();

  AbbrevNo = 0;
  AdvanceStream();
}

bool Deserializer::SkipToBlock(unsigned BlockID) {
  assert (!inRecord());

  AdvanceStream();
  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);

  unsigned BlockLevel = BlockStack.size();

  while (!AtEnd() &&
         BlockLevel == BlockStack.size() &&
         getCurrentBlockID() != BlockID)
    SkipBlock();

  return !(AtEnd() || BlockLevel != BlockStack.size());
}

Deserializer::Location Deserializer::getCurrentBlockLocation() {
  if (!inRecord())
    AdvanceStream();

  return BlockStack.back();
}

bool Deserializer::JumpTo(const Location& Loc) {

  assert (!inRecord());

  AdvanceStream();

  assert (!BlockStack.empty() || AtEnd());

  uint64_t LastBPos = StreamStart;

  while (!BlockStack.empty()) {

    LastBPos = BlockStack.back().BitNo;

    // Determine of the current block contains the location of the block
    // we are looking for.
    if (BlockStack.back().contains(Loc)) {
      // We found the enclosing block.  We must first POP it off to
      // destroy any accumulated context within the block scope.  We then
      // jump to the position of the block and enter it.
      Stream.JumpToBit(LastBPos);

      if (BlockStack.size() == Stream.BlockScope.size())
        Stream.PopBlockScope();

      BlockStack.pop_back();

      AbbrevNo = 0;
      AdvanceStream();
      assert (AbbrevNo == bitc::ENTER_SUBBLOCK);

      Stream.EnterSubBlock(BlockStack.back().BlockID);
      break;
    }

    // This block does not contain the block we are looking for.  Pop it.
    if (BlockStack.size() == Stream.BlockScope.size())
      Stream.PopBlockScope();

    BlockStack.pop_back();

  }

  // Check if we have popped our way to the outermost scope.  If so,
  // we need to adjust our position.
  if (BlockStack.empty()) {
    assert (Stream.BlockScope.empty());

    Stream.JumpToBit(Loc.BitNo < LastBPos ? StreamStart : LastBPos);
    AbbrevNo = 0;
    AdvanceStream();
  }

  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
  assert (!BlockStack.empty());

  while (!AtEnd() && BlockStack.back() != Loc) {
    if (BlockStack.back().contains(Loc)) {
      Stream.EnterSubBlock(BlockStack.back().BlockID);
      AbbrevNo = 0;
      AdvanceStream();
      continue;
    }
    else
      SkipBlock();
  }

  if (AtEnd())
    return false;

  assert (BlockStack.back() == Loc);

  return true;
}

void Deserializer::Rewind() {
  while (!Stream.BlockScope.empty())
    Stream.PopBlockScope();

  while (!BlockStack.empty())
    BlockStack.pop_back();

  Stream.JumpToBit(StreamStart);
  AbbrevNo = 0;
}

unsigned Deserializer::getCurrentBlockID() {
  if (!inRecord())
    AdvanceStream();

  return BlockStack.back().BlockID;
}

unsigned Deserializer::getRecordCode() {
  if (!inRecord()) {
    AdvanceStream();
    assert (AbbrevNo >= bitc::UNABBREV_RECORD);
    ReadRecord();
  }

  return RecordCode;
}

bool Deserializer::FinishedBlock(Location BlockLoc) {
  if (!inRecord())
    AdvanceStream();

  for (llvm::SmallVector<Location,8>::reverse_iterator
        I=BlockStack.rbegin(), E=BlockStack.rend(); I!=E; ++I)
      if (*I == BlockLoc)
        return false;

  return true;
}

unsigned Deserializer::getAbbrevNo() {
  if (!inRecord())
    AdvanceStream();

  return AbbrevNo;
}

bool Deserializer::AtEnd() {
  if (inRecord())
    return false;

  if (!AdvanceStream())
    return true;

  return false;
}

uint64_t Deserializer::ReadInt() {
  // FIXME: Any error recovery/handling with incomplete or bad files?
  if (!inRecord())
    ReadRecord();

  return Record[RecIdx++];
}

int64_t Deserializer::ReadSInt() {
  uint64_t x = ReadInt();
  int64_t magnitude = x >> 1;
  return x & 0x1 ? -magnitude : magnitude;
}

char* Deserializer::ReadCStr(char* cstr, unsigned MaxLen, bool isNullTerm) {
  if (cstr == NULL)
    MaxLen = 0; // Zero this just in case someone does something funny.

  unsigned len = ReadInt();

  assert (MaxLen == 0 || (len + (isNullTerm ? 1 : 0)) <= MaxLen);

  if (!cstr)
    cstr = new char[len + (isNullTerm ? 1 : 0)];

  assert (cstr != NULL);

  for (unsigned i = 0; i < len; ++i)
    cstr[i] = (char) ReadInt();

  if (isNullTerm)
    cstr[len] = '\0';

  return cstr;
}

void Deserializer::ReadCStr(std::vector<char>& buff, bool isNullTerm,
                            unsigned Idx) {

  unsigned len = ReadInt();

  // If Idx is beyond the current before size, reduce Idx to refer to the
  // element after the last element.
  if (Idx > buff.size())
    Idx = buff.size();

  buff.reserve(len+Idx);
  buff.resize(Idx);

  for (unsigned i = 0; i < len; ++i)
    buff.push_back((char) ReadInt());

  if (isNullTerm)
    buff.push_back('\0');
}

void Deserializer::RegisterPtr(const SerializedPtrID& PtrId,
                               const void* Ptr) {

  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  assert (!HasFinalPtr(E) && "Pointer already registered.");

#ifdef DEBUG_BACKPATCH
  llvm::cerr << "RegisterPtr: " << PtrId << " => " << Ptr << "\n";
#endif

  SetPtr(E,Ptr);
}

void Deserializer::ReadUIntPtr(uintptr_t& PtrRef,
                               const SerializedPtrID& PtrId,
                               bool AllowBackpatch) {
  if (PtrId == 0) {
    PtrRef = 0;
    return;
  }

  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  if (HasFinalPtr(E)) {
    PtrRef = GetFinalPtr(E);

#ifdef DEBUG_BACKPATCH
    llvm::cerr << "ReadUintPtr: " << PtrId
               << " <-- " <<  (void*) GetFinalPtr(E) << '\n';
#endif
  }
  else {
    assert (AllowBackpatch &&
            "Client forbids backpatching for this pointer.");

#ifdef DEBUG_BACKPATCH
    llvm::cerr << "ReadUintPtr: " << PtrId << " (NO PTR YET)\n";
#endif

    // Register backpatch.  Check the freelist for a BPNode.
    BPNode* N;

    if (FreeList) {
      N = FreeList;
      FreeList = FreeList->Next;
    }
    else // No available BPNode.  Allocate one.
      N = (BPNode*) Allocator.Allocate<BPNode>();

    new (N) BPNode(GetBPNode(E),PtrRef);
    SetBPNode(E,N);
  }
}

uintptr_t Deserializer::ReadInternalRefPtr() {
  SerializedPtrID PtrId = ReadPtrID();

  assert (PtrId != 0 && "References cannot refer the NULL address.");

  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  assert (HasFinalPtr(E) &&
          "Cannot backpatch references.  Object must be already deserialized.");

  return GetFinalPtr(E);
}

void Deserializer::BPEntry::SetPtr(BPNode*& FreeList, void* P) {
  BPNode* Last = NULL;

  for (BPNode* N = Head; N != NULL; N=N->Next) {
    Last = N;
    N->PtrRef |= reinterpret_cast<uintptr_t>(P);
  }

  if (Last) {
    Last->Next = FreeList;
    FreeList = Head;
  }

  Ptr = const_cast<void*>(P);
}

#define INT_READ(TYPE)\
void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
  X = (TYPE) D.ReadInt(); }

INT_READ(bool)
INT_READ(unsigned char)
INT_READ(unsigned short)
INT_READ(unsigned int)
INT_READ(unsigned long)

#define SINT_READ(TYPE)\
void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
  X = (TYPE) D.ReadSInt(); }

INT_READ(signed char)
INT_READ(signed short)
INT_READ(signed int)
INT_READ(signed long)
<commit_msg>Remove dead code.<commit_after>//==- Deserialize.cpp - Generic Object Serialization to Bitcode --*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the internal methods used for object serialization.
//
//===----------------------------------------------------------------------===//

#include "llvm/Bitcode/Deserialize.h"

#ifdef DEBUG_BACKPATCH
#include "llvm/Support/Streams.h"
#endif

using namespace llvm;

Deserializer::Deserializer(BitstreamReader& stream)
  : Stream(stream), RecIdx(0), FreeList(NULL), AbbrevNo(0), RecordCode(0) {

    StreamStart = Stream.GetCurrentBitNo();
}

Deserializer::~Deserializer() {
  assert (RecIdx >= Record.size() &&
          "Still scanning bitcode record when deserialization completed.");

#ifdef DEBUG_BACKPATCH
  for (MapTy::iterator I=BPatchMap.begin(), E=BPatchMap.end(); I!=E; ++I)
    assert (I->first.hasFinalPtr() &&
            "Some pointers were not backpatched.");
#endif
}

bool Deserializer::inRecord() {
  if (Record.size() > 0) {
    if (RecIdx >= Record.size()) {
      RecIdx = 0;
      Record.clear();
      AbbrevNo = 0;
      return false;
    }
    else
      return true;
  }

  return false;
}

bool Deserializer::AdvanceStream() {
  assert (!inRecord() &&
          "Cannot advance stream.  Still processing a record.");

  if (AbbrevNo == bitc::ENTER_SUBBLOCK ||
      AbbrevNo >= bitc::UNABBREV_RECORD)
    return true;

  while (!Stream.AtEndOfStream()) {

    uint64_t Pos = Stream.GetCurrentBitNo();
    AbbrevNo = Stream.ReadCode();

    switch (AbbrevNo) {
      case bitc::ENTER_SUBBLOCK: {
        unsigned id = Stream.ReadSubBlockID();

        // Determine the extent of the block.  This is useful for jumping around
        // the stream.  This is hack: we read the header of the block, save
        // the length, and then revert the bitstream to a location just before
        // the block is entered.
        uint64_t BPos = Stream.GetCurrentBitNo();
        Stream.ReadVBR(bitc::CodeLenWidth); // Skip the code size.
        Stream.SkipToWord();
        unsigned NumWords = Stream.Read(bitc::BlockSizeWidth);
        Stream.JumpToBit(BPos);

        BlockStack.push_back(Location(Pos,id,NumWords));
        break;
      }

      case bitc::END_BLOCK: {
        bool x = Stream.ReadBlockEnd();
        assert(!x && "Error at block end.");
        BlockStack.pop_back();
        continue;
      }

      case bitc::DEFINE_ABBREV:
        Stream.ReadAbbrevRecord();
        continue;

      default:
        break;
    }

    return true;
  }

  return false;
}

void Deserializer::ReadRecord() {

  while (AdvanceStream() && AbbrevNo == bitc::ENTER_SUBBLOCK) {
    assert (!BlockStack.empty());
    Stream.EnterSubBlock(BlockStack.back().BlockID);
    AbbrevNo = 0;
  }

  if (Stream.AtEndOfStream())
    return;

  assert (Record.empty());
  assert (AbbrevNo >= bitc::UNABBREV_RECORD);
  RecordCode = Stream.ReadRecord(AbbrevNo,Record);
  assert (Record.size() > 0);
}

void Deserializer::SkipBlock() {
  assert (!inRecord());

  if (AtEnd())
    return;

  AdvanceStream();

  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
  BlockStack.pop_back();
  Stream.SkipBlock();

  AbbrevNo = 0;
  AdvanceStream();
}

bool Deserializer::SkipToBlock(unsigned BlockID) {
  assert (!inRecord());

  AdvanceStream();
  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);

  unsigned BlockLevel = BlockStack.size();

  while (!AtEnd() &&
         BlockLevel == BlockStack.size() &&
         getCurrentBlockID() != BlockID)
    SkipBlock();

  return !(AtEnd() || BlockLevel != BlockStack.size());
}

Deserializer::Location Deserializer::getCurrentBlockLocation() {
  if (!inRecord())
    AdvanceStream();

  return BlockStack.back();
}

bool Deserializer::JumpTo(const Location& Loc) {

  assert (!inRecord());

  AdvanceStream();

  assert (!BlockStack.empty() || AtEnd());

  uint64_t LastBPos = StreamStart;

  while (!BlockStack.empty()) {

    LastBPos = BlockStack.back().BitNo;

    // Determine of the current block contains the location of the block
    // we are looking for.
    if (BlockStack.back().contains(Loc)) {
      // We found the enclosing block.  We must first POP it off to
      // destroy any accumulated context within the block scope.  We then
      // jump to the position of the block and enter it.
      Stream.JumpToBit(LastBPos);

      if (BlockStack.size() == Stream.BlockScope.size())
        Stream.PopBlockScope();

      BlockStack.pop_back();

      AbbrevNo = 0;
      AdvanceStream();
      assert (AbbrevNo == bitc::ENTER_SUBBLOCK);

      Stream.EnterSubBlock(BlockStack.back().BlockID);
      break;
    }

    // This block does not contain the block we are looking for.  Pop it.
    if (BlockStack.size() == Stream.BlockScope.size())
      Stream.PopBlockScope();

    BlockStack.pop_back();

  }

  // Check if we have popped our way to the outermost scope.  If so,
  // we need to adjust our position.
  if (BlockStack.empty()) {
    assert (Stream.BlockScope.empty());

    Stream.JumpToBit(Loc.BitNo < LastBPos ? StreamStart : LastBPos);
    AbbrevNo = 0;
    AdvanceStream();
  }

  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
  assert (!BlockStack.empty());

  while (!AtEnd() && BlockStack.back() != Loc) {
    if (BlockStack.back().contains(Loc)) {
      Stream.EnterSubBlock(BlockStack.back().BlockID);
      AbbrevNo = 0;
      AdvanceStream();
      continue;
    }
    else
      SkipBlock();
  }

  if (AtEnd())
    return false;

  assert (BlockStack.back() == Loc);

  return true;
}

void Deserializer::Rewind() {
  while (!Stream.BlockScope.empty())
    Stream.PopBlockScope();

  while (!BlockStack.empty())
    BlockStack.pop_back();

  Stream.JumpToBit(StreamStart);
  AbbrevNo = 0;
}

unsigned Deserializer::getCurrentBlockID() {
  if (!inRecord())
    AdvanceStream();

  return BlockStack.back().BlockID;
}

unsigned Deserializer::getRecordCode() {
  if (!inRecord()) {
    AdvanceStream();
    assert (AbbrevNo >= bitc::UNABBREV_RECORD);
    ReadRecord();
  }

  return RecordCode;
}

bool Deserializer::FinishedBlock(Location BlockLoc) {
  if (!inRecord())
    AdvanceStream();

  for (llvm::SmallVector<Location,8>::reverse_iterator
        I=BlockStack.rbegin(), E=BlockStack.rend(); I!=E; ++I)
      if (*I == BlockLoc)
        return false;

  return true;
}

unsigned Deserializer::getAbbrevNo() {
  if (!inRecord())
    AdvanceStream();

  return AbbrevNo;
}

bool Deserializer::AtEnd() {
  if (inRecord())
    return false;

  if (!AdvanceStream())
    return true;

  return false;
}

uint64_t Deserializer::ReadInt() {
  // FIXME: Any error recovery/handling with incomplete or bad files?
  if (!inRecord())
    ReadRecord();

  return Record[RecIdx++];
}

int64_t Deserializer::ReadSInt() {
  uint64_t x = ReadInt();
  int64_t magnitude = x >> 1;
  return x & 0x1 ? -magnitude : magnitude;
}

char* Deserializer::ReadCStr(char* cstr, unsigned MaxLen, bool isNullTerm) {
  if (cstr == NULL)
    MaxLen = 0; // Zero this just in case someone does something funny.

  unsigned len = ReadInt();

  assert (MaxLen == 0 || (len + (isNullTerm ? 1 : 0)) <= MaxLen);

  if (!cstr)
    cstr = new char[len + (isNullTerm ? 1 : 0)];

  assert (cstr != NULL);

  for (unsigned i = 0; i < len; ++i)
    cstr[i] = (char) ReadInt();

  if (isNullTerm)
    cstr[len] = '\0';

  return cstr;
}

void Deserializer::ReadCStr(std::vector<char>& buff, bool isNullTerm,
                            unsigned Idx) {

  unsigned len = ReadInt();

  // If Idx is beyond the current before size, reduce Idx to refer to the
  // element after the last element.
  if (Idx > buff.size())
    Idx = buff.size();

  buff.reserve(len+Idx);
  buff.resize(Idx);

  for (unsigned i = 0; i < len; ++i)
    buff.push_back((char) ReadInt());

  if (isNullTerm)
    buff.push_back('\0');
}

void Deserializer::RegisterPtr(const SerializedPtrID& PtrId,
                               const void* Ptr) {

  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  assert (!HasFinalPtr(E) && "Pointer already registered.");

#ifdef DEBUG_BACKPATCH
  llvm::cerr << "RegisterPtr: " << PtrId << " => " << Ptr << "\n";
#endif

  SetPtr(E,Ptr);
}

void Deserializer::ReadUIntPtr(uintptr_t& PtrRef,
                               const SerializedPtrID& PtrId,
                               bool AllowBackpatch) {
  if (PtrId == 0) {
    PtrRef = 0;
    return;
  }

  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  if (HasFinalPtr(E)) {
    PtrRef = GetFinalPtr(E);

#ifdef DEBUG_BACKPATCH
    llvm::cerr << "ReadUintPtr: " << PtrId
               << " <-- " <<  (void*) GetFinalPtr(E) << '\n';
#endif
  }
  else {
    assert (AllowBackpatch &&
            "Client forbids backpatching for this pointer.");

#ifdef DEBUG_BACKPATCH
    llvm::cerr << "ReadUintPtr: " << PtrId << " (NO PTR YET)\n";
#endif

    // Register backpatch.  Check the freelist for a BPNode.
    BPNode* N;

    if (FreeList) {
      N = FreeList;
      FreeList = FreeList->Next;
    }
    else // No available BPNode.  Allocate one.
      N = (BPNode*) Allocator.Allocate<BPNode>();

    new (N) BPNode(GetBPNode(E),PtrRef);
    SetBPNode(E,N);
  }
}

uintptr_t Deserializer::ReadInternalRefPtr() {
  SerializedPtrID PtrId = ReadPtrID();

  assert (PtrId != 0 && "References cannot refer the NULL address.");

  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  assert (HasFinalPtr(E) &&
          "Cannot backpatch references.  Object must be already deserialized.");

  return GetFinalPtr(E);
}

void Deserializer::BPEntry::SetPtr(BPNode*& FreeList, void* P) {
  BPNode* Last = NULL;

  for (BPNode* N = Head; N != NULL; N=N->Next) {
    Last = N;
    N->PtrRef |= reinterpret_cast<uintptr_t>(P);
  }

  if (Last) {
    Last->Next = FreeList;
    FreeList = Head;
  }

  Ptr = const_cast<void*>(P);
}

#define INT_READ(TYPE)\
void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
  X = (TYPE) D.ReadInt(); }

INT_READ(bool)
INT_READ(unsigned char)
INT_READ(unsigned short)
INT_READ(unsigned int)
INT_READ(unsigned long)

#define SINT_READ(TYPE)\
void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
  X = (TYPE) D.ReadSInt(); }

INT_READ(signed char)
INT_READ(signed short)
INT_READ(signed int)
INT_READ(signed long)
<|endoftext|>