<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

//
//  W A R N I N G
//  -------------
//
// This file is not part of the Qt API.  It exists for the convenience
// of other Qt classes.  This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//

#include <QtCore/qstringlist.h>
#include <QtCore/qlist.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qdebug.h>
#include <private/qcore_mac_p.h>

#include <qaudiodeviceinfo.h>
#include "qaudio_mac_p.h"
#include "qaudiodeviceinfo_mac_p.h"

QT_BEGIN_NAMESPACE

QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray const& handle, QAudio::Mode)
{
    QDataStream ds(handle);
    quint32 did, tm;

    ds >> did >> tm >> name;
    deviceId = AudioDeviceID(did);
    mode = QAudio::Mode(tm);
}

bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const
{
    return format.codec() == QString::fromLatin1("audio/pcm");
}

QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const
{
    QAudioFormat    rc;

    UInt32  propSize = 0;

    if (AudioDeviceGetPropertyInfo(deviceId,
                                    0,
                                    mode == QAudio::AudioInput,
                                    kAudioDevicePropertyStreams,
                                    &propSize,
                                    0) == noErr) {

        const int sc = propSize / sizeof(AudioStreamID);

        if (sc > 0) {
            AudioStreamID*  streams = new AudioStreamID[sc];

            if (AudioDeviceGetProperty(deviceId,
                                        0,
                                        mode == QAudio::AudioInput,
                                        kAudioDevicePropertyStreams,
                                        &propSize,
                                        streams) == noErr) {

                for (int i = 0; i < sc; ++i) {
                    if (AudioStreamGetPropertyInfo(streams[i],
                                                    0,
                                                    kAudioStreamPropertyPhysicalFormat,
                                                    &propSize,
                                                    0) == noErr) {

                        AudioStreamBasicDescription sf;

                        if (AudioStreamGetProperty(streams[i],
                                                    0,
                                                    kAudioStreamPropertyPhysicalFormat,
                                                    &propSize,
                                                    &sf) == noErr) {
                            rc = toQAudioFormat(sf);
                            break;
                        }
                    }
                }
            }

            delete streams;
        }
    }

    return rc;
}

QString QAudioDeviceInfoInternal::deviceName() const
{
    return name;
}

QStringList QAudioDeviceInfoInternal::supportedCodecs()
{
    return QStringList() << QString::fromLatin1("audio/pcm");
}

QList<int> QAudioDeviceInfoInternal::supportedSampleRates()
{
    QSet<int>  rc;

    // Add some common frequencies
    rc << 8000 << 11025 << 22050 << 44100;

    //
    UInt32  propSize = 0;

    if (AudioDeviceGetPropertyInfo(deviceId,
                                    0,
                                    mode == QAudio::AudioInput,
                                    kAudioDevicePropertyAvailableNominalSampleRates,
                                    &propSize,
                                    0) == noErr) {

        const int pc = propSize / sizeof(AudioValueRange);

        if (pc > 0) {
            AudioValueRange*    vr = new AudioValueRange[pc];

            if (AudioDeviceGetProperty(deviceId,
                                        0,
                                        mode == QAudio::AudioInput,
                                        kAudioDevicePropertyAvailableNominalSampleRates,
                                        &propSize,
                                        vr) == noErr) {

                for (int i = 0; i < pc; ++i)
                    rc << vr[i].mMaximum;
            }

            delete vr;
        }
    }

    return rc.toList();
}

QList<int> QAudioDeviceInfoInternal::supportedChannelCounts()
{
    QList<int>  rc;

    // Can mix down to 1 channel
    rc << 1;

    UInt32  propSize = 0;
    int     channels = 0;

    if (AudioDeviceGetPropertyInfo(deviceId,
                                    0,
                                    mode == QAudio::AudioInput,
                                    kAudioDevicePropertyStreamConfiguration,
                                    &propSize,
                                    0) == noErr) {

        AudioBufferList* audioBufferList = static_cast<AudioBufferList*>(qMalloc(propSize));

        if (audioBufferList != 0) {
            if (AudioDeviceGetProperty(deviceId,
                                        0,
                                        mode == QAudio::AudioInput,
                                        kAudioDevicePropertyStreamConfiguration,
                                        &propSize,
                                        audioBufferList) == noErr) {

                for (int i = 0; i < int(audioBufferList->mNumberBuffers); ++i) {
                    channels += audioBufferList->mBuffers[i].mNumberChannels;
                    rc << channels;
                }
            }

            qFree(audioBufferList);
        }
    }

    return rc;
}

QList<int> QAudioDeviceInfoInternal::supportedSampleSizes()
{
    return QList<int>() << 8 << 16 << 24 << 32 << 64;
}

QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::supportedByteOrders()
{
    return QList<QAudioFormat::Endian>() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian;
}

QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::supportedSampleTypes()
{
    return QList<QAudioFormat::SampleType>() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float;
}

static QByteArray get_device_info(AudioDeviceID audioDevice, QAudio::Mode mode)
{
    UInt32      size;
    QByteArray  device;
    QDataStream ds(&device, QIODevice::WriteOnly);
    AudioStreamBasicDescription     sf;
    CFStringRef name;
    Boolean     isInput = mode == QAudio::AudioInput;

    // Id
    ds << quint32(audioDevice);

    // Mode
    size = sizeof(AudioStreamBasicDescription);
    if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioDevicePropertyStreamFormat,
                                &size, &sf) != noErr) {
        return QByteArray();
    }
    ds << quint32(mode);

    // Name
    size = sizeof(CFStringRef);
    if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioObjectPropertyName,
                                &size, &name) != noErr) {
        qWarning() << "QAudioDeviceInfo: Unable to find device name";
    }
    ds << QCFString::toQString(name);

    CFRelease(name);

    return device;
}

QByteArray QAudioDeviceInfoInternal::defaultInputDevice()
{
    AudioDeviceID   audioDevice;
    UInt32          size = sizeof(audioDevice);

    if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size,
                                    &audioDevice) != noErr) {
        qWarning() << "QAudioDeviceInfo: Unable to find default input device";
        return QByteArray();
    }

    return get_device_info(audioDevice, QAudio::AudioInput);
}

QByteArray QAudioDeviceInfoInternal::defaultOutputDevice()
{
    AudioDeviceID audioDevice;
    UInt32        size = sizeof(audioDevice);

    if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size,
                                    &audioDevice) != noErr) {
        qWarning() << "QAudioDeviceInfo: Unable to find default output device";
        return QByteArray();
    }

    return get_device_info(audioDevice, QAudio::AudioOutput);
}

QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode)
{
    QList<QByteArray>   devices;

    UInt32  propSize = 0;

    if (AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propSize, 0) == noErr) {

        const int dc = propSize / sizeof(AudioDeviceID);

        if (dc > 0) {
            AudioDeviceID*  audioDevices = new AudioDeviceID[dc];

            if (AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propSize, audioDevices) == noErr) {
                for (int i = 0; i < dc; ++i) {
                    QByteArray info = get_device_info(audioDevices[i], mode);
                    if (!info.isNull())
                        devices << info;
                }
            }

            delete audioDevices;
        }
    }

    return devices;
}

QT_END_NAMESPACE

<commit_msg>Remove use of Qt private API.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

//
//  W A R N I N G
//  -------------
//
// This file is not part of the Qt API.  It exists for the convenience
// of other Qt classes.  This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//

#include <QtCore/qstringlist.h>
#include <QtCore/qlist.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qdebug.h>

#include <qaudiodeviceinfo.h>
#include "qaudio_mac_p.h"
#include "qaudiodeviceinfo_mac_p.h"

QT_BEGIN_NAMESPACE

// XXX: remove at some future date
static inline QString cfStringToQString(CFStringRef str)
{
    CFIndex length = CFStringGetLength(str);
    const UniChar *chars = CFStringGetCharactersPtr(str);
    if (chars)
        return QString(reinterpret_cast<const QChar *>(chars), length);

    UniChar buffer[length];
    CFStringGetCharacters(str, CFRangeMake(0, length), buffer);
    return QString(reinterpret_cast<const QChar *>(buffer), length);
}

QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray const& handle, QAudio::Mode)
{
    QDataStream ds(handle);
    quint32 did, tm;

    ds >> did >> tm >> name;
    deviceId = AudioDeviceID(did);
    mode = QAudio::Mode(tm);
}

bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const
{
    return format.codec() == QString::fromLatin1("audio/pcm");
}

QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const
{
    QAudioFormat    rc;

    UInt32  propSize = 0;

    if (AudioDeviceGetPropertyInfo(deviceId,
                                    0,
                                    mode == QAudio::AudioInput,
                                    kAudioDevicePropertyStreams,
                                    &propSize,
                                    0) == noErr) {

        const int sc = propSize / sizeof(AudioStreamID);

        if (sc > 0) {
            AudioStreamID*  streams = new AudioStreamID[sc];

            if (AudioDeviceGetProperty(deviceId,
                                        0,
                                        mode == QAudio::AudioInput,
                                        kAudioDevicePropertyStreams,
                                        &propSize,
                                        streams) == noErr) {

                for (int i = 0; i < sc; ++i) {
                    if (AudioStreamGetPropertyInfo(streams[i],
                                                    0,
                                                    kAudioStreamPropertyPhysicalFormat,
                                                    &propSize,
                                                    0) == noErr) {

                        AudioStreamBasicDescription sf;

                        if (AudioStreamGetProperty(streams[i],
                                                    0,
                                                    kAudioStreamPropertyPhysicalFormat,
                                                    &propSize,
                                                    &sf) == noErr) {
                            rc = toQAudioFormat(sf);
                            break;
                        }
                    }
                }
            }

            delete streams;
        }
    }

    return rc;
}

QString QAudioDeviceInfoInternal::deviceName() const
{
    return name;
}

QStringList QAudioDeviceInfoInternal::supportedCodecs()
{
    return QStringList() << QString::fromLatin1("audio/pcm");
}

QList<int> QAudioDeviceInfoInternal::supportedSampleRates()
{
    QSet<int>  rc;

    // Add some common frequencies
    rc << 8000 << 11025 << 22050 << 44100;

    //
    UInt32  propSize = 0;

    if (AudioDeviceGetPropertyInfo(deviceId,
                                    0,
                                    mode == QAudio::AudioInput,
                                    kAudioDevicePropertyAvailableNominalSampleRates,
                                    &propSize,
                                    0) == noErr) {

        const int pc = propSize / sizeof(AudioValueRange);

        if (pc > 0) {
            AudioValueRange*    vr = new AudioValueRange[pc];

            if (AudioDeviceGetProperty(deviceId,
                                        0,
                                        mode == QAudio::AudioInput,
                                        kAudioDevicePropertyAvailableNominalSampleRates,
                                        &propSize,
                                        vr) == noErr) {

                for (int i = 0; i < pc; ++i)
                    rc << vr[i].mMaximum;
            }

            delete vr;
        }
    }

    return rc.toList();
}

QList<int> QAudioDeviceInfoInternal::supportedChannelCounts()
{
    QList<int>  rc;

    // Can mix down to 1 channel
    rc << 1;

    UInt32  propSize = 0;
    int     channels = 0;

    if (AudioDeviceGetPropertyInfo(deviceId,
                                    0,
                                    mode == QAudio::AudioInput,
                                    kAudioDevicePropertyStreamConfiguration,
                                    &propSize,
                                    0) == noErr) {

        AudioBufferList* audioBufferList = static_cast<AudioBufferList*>(qMalloc(propSize));

        if (audioBufferList != 0) {
            if (AudioDeviceGetProperty(deviceId,
                                        0,
                                        mode == QAudio::AudioInput,
                                        kAudioDevicePropertyStreamConfiguration,
                                        &propSize,
                                        audioBufferList) == noErr) {

                for (int i = 0; i < int(audioBufferList->mNumberBuffers); ++i) {
                    channels += audioBufferList->mBuffers[i].mNumberChannels;
                    rc << channels;
                }
            }

            qFree(audioBufferList);
        }
    }

    return rc;
}

QList<int> QAudioDeviceInfoInternal::supportedSampleSizes()
{
    return QList<int>() << 8 << 16 << 24 << 32 << 64;
}

QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::supportedByteOrders()
{
    return QList<QAudioFormat::Endian>() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian;
}

QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::supportedSampleTypes()
{
    return QList<QAudioFormat::SampleType>() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float;
}

static QByteArray get_device_info(AudioDeviceID audioDevice, QAudio::Mode mode)
{
    UInt32      size;
    QByteArray  device;
    QDataStream ds(&device, QIODevice::WriteOnly);
    AudioStreamBasicDescription     sf;
    CFStringRef name;
    Boolean     isInput = mode == QAudio::AudioInput;

    // Id
    ds << quint32(audioDevice);

    // Mode
    size = sizeof(AudioStreamBasicDescription);
    if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioDevicePropertyStreamFormat,
                                &size, &sf) != noErr) {
        return QByteArray();
    }
    ds << quint32(mode);

    // Name
    size = sizeof(CFStringRef);
    if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioObjectPropertyName,
                                &size, &name) != noErr) {
        qWarning() << "QAudioDeviceInfo: Unable to find device name";
    }
    ds << cfStringToQString(name);

    CFRelease(name);

    return device;
}

QByteArray QAudioDeviceInfoInternal::defaultInputDevice()
{
    AudioDeviceID   audioDevice;
    UInt32          size = sizeof(audioDevice);

    if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size,
                                    &audioDevice) != noErr) {
        qWarning() << "QAudioDeviceInfo: Unable to find default input device";
        return QByteArray();
    }

    return get_device_info(audioDevice, QAudio::AudioInput);
}

QByteArray QAudioDeviceInfoInternal::defaultOutputDevice()
{
    AudioDeviceID audioDevice;
    UInt32        size = sizeof(audioDevice);

    if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size,
                                    &audioDevice) != noErr) {
        qWarning() << "QAudioDeviceInfo: Unable to find default output device";
        return QByteArray();
    }

    return get_device_info(audioDevice, QAudio::AudioOutput);
}

QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode)
{
    QList<QByteArray>   devices;

    UInt32  propSize = 0;

    if (AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propSize, 0) == noErr) {

        const int dc = propSize / sizeof(AudioDeviceID);

        if (dc > 0) {
            AudioDeviceID*  audioDevices = new AudioDeviceID[dc];

            if (AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propSize, audioDevices) == noErr) {
                for (int i = 0; i < dc; ++i) {
                    QByteArray info = get_device_info(audioDevices[i], mode);
                    if (!info.isNull())
                        devices << info;
                }
            }

            delete audioDevices;
        }
    }

    return devices;
}

QT_END_NAMESPACE

<|endoftext|>


<commit_before>// Copyright (C) 2014 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <libaddressinput/synonyms.h>

#include <libaddressinput/address_data.h>
#include <libaddressinput/address_field.h>
#include <libaddressinput/preload_supplier.h>

#include <cassert>
#include <cstddef>

#include "language.h"
#include "lookup_key.h"
#include "region_data_constants.h"
#include "rule.h"
#include "util/string_compare.h"

namespace i18n {
namespace addressinput {

Synonyms::Synonyms(const PreloadSupplier* supplier)
    : supplier_(supplier),
      compare_(new StringCompare) {
  assert(supplier_ != NULL);
}

Synonyms::~Synonyms() {}

void Synonyms::NormalizeForDisplay(AddressData* address) const {
  assert(address != NULL);
  assert(supplier_->IsLoaded(address->region_code));

  AddressData region_address;
  region_address.region_code = address->region_code;
  LookupKey parent_key;
  parent_key.FromAddress(region_address);
  const Rule* parent_rule = supplier_->GetRule(parent_key);
  assert(parent_rule != NULL);

  const Language& best_language =
      ChooseBestAddressLanguage(*parent_rule, Language(address->language_code));

  LookupKey lookup_key;
  for (size_t depth = 1; depth < arraysize(LookupKey::kHierarchy); ++depth) {
    AddressField field = LookupKey::kHierarchy[depth];
    if (address->IsFieldEmpty(field)) {
      return;
    }
    const std::string& field_value = address->GetFieldValue(field);
    bool no_match_found_yet = true;
    for (std::vector<std::string>::const_iterator
         key_it = parent_rule->GetSubKeys().begin();
         key_it != parent_rule->GetSubKeys().end(); ++key_it) {
      lookup_key.FromLookupKey(parent_key, *key_it);
      const Rule* rule = supplier_->GetRule(lookup_key);
      assert(rule != NULL);

      bool matches_latin_name =
          compare_->NaturalEquals(field_value, rule->GetLatinName());
      bool matches_local_name_id =
          compare_->NaturalEquals(field_value, *key_it) ||
          compare_->NaturalEquals(field_value, rule->GetName());
      if (matches_latin_name || matches_local_name_id) {
        address->SetFieldValue(
            field, matches_latin_name ? rule->GetLatinName() : *key_it);
        no_match_found_yet = false;
        parent_key.FromLookupKey(parent_key, *key_it);
        parent_rule = supplier_->GetRule(parent_key);
        assert(parent_rule != NULL);
        break;
      }
    }
    if (no_match_found_yet) {
      return;  // Abort search.
    }
  }
}

}  // namespace addressinput
}  // namespace i18n
<commit_msg>Delete unused call to ChooseBestAddressLanguage().<commit_after>// Copyright (C) 2014 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <libaddressinput/synonyms.h>

#include <libaddressinput/address_data.h>
#include <libaddressinput/address_field.h>
#include <libaddressinput/preload_supplier.h>

#include <cassert>
#include <cstddef>

#include "lookup_key.h"
#include "region_data_constants.h"
#include "rule.h"
#include "util/string_compare.h"

namespace i18n {
namespace addressinput {

Synonyms::Synonyms(const PreloadSupplier* supplier)
    : supplier_(supplier),
      compare_(new StringCompare) {
  assert(supplier_ != NULL);
}

Synonyms::~Synonyms() {}

void Synonyms::NormalizeForDisplay(AddressData* address) const {
  assert(address != NULL);
  assert(supplier_->IsLoaded(address->region_code));

  AddressData region_address;
  region_address.region_code = address->region_code;
  LookupKey parent_key;
  parent_key.FromAddress(region_address);
  const Rule* parent_rule = supplier_->GetRule(parent_key);
  assert(parent_rule != NULL);

  LookupKey lookup_key;
  for (size_t depth = 1; depth < arraysize(LookupKey::kHierarchy); ++depth) {
    AddressField field = LookupKey::kHierarchy[depth];
    if (address->IsFieldEmpty(field)) {
      return;
    }
    const std::string& field_value = address->GetFieldValue(field);
    bool no_match_found_yet = true;
    for (std::vector<std::string>::const_iterator
         key_it = parent_rule->GetSubKeys().begin();
         key_it != parent_rule->GetSubKeys().end(); ++key_it) {
      lookup_key.FromLookupKey(parent_key, *key_it);
      const Rule* rule = supplier_->GetRule(lookup_key);
      assert(rule != NULL);

      bool matches_latin_name =
          compare_->NaturalEquals(field_value, rule->GetLatinName());
      bool matches_local_name_id =
          compare_->NaturalEquals(field_value, *key_it) ||
          compare_->NaturalEquals(field_value, rule->GetName());
      if (matches_latin_name || matches_local_name_id) {
        address->SetFieldValue(
            field, matches_latin_name ? rule->GetLatinName() : *key_it);
        no_match_found_yet = false;
        parent_key.FromLookupKey(parent_key, *key_it);
        parent_rule = supplier_->GetRule(parent_key);
        assert(parent_rule != NULL);
        break;
      }
    }
    if (no_match_found_yet) {
      return;  // Abort search.
    }
  }
}

}  // namespace addressinput
}  // namespace i18n
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "camera.h"
#include "ui_camera.h"
#include "videosettings.h"
#include "imagesettings.h"

#include <qmediaservice.h>
#include <qmediarecorder.h>
#include <qcamera.h>
#include <qcameraviewfinder.h>

#include <qmessagebox.h>
#include <qpalette.h>

#include <QtGui>

#if (defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)) && QT_VERSION >= 0x040700
#define HAVE_CAMERA_BUTTONS
#endif

Camera::Camera(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Camera),
    camera(0),
    imageCapture(0),
    mediaRecorder(0)
{
    ui->setupUi(this);

    //Camera devices:
    QByteArray cameraDevice;

    QActionGroup *videoDevicesGroup = new QActionGroup(this);
    videoDevicesGroup->setExclusive(true);
    foreach(const QByteArray &deviceName, QCamera::availableDevices()) {
        QString description = camera->deviceDescription(deviceName);
        QAction *videoDeviceAction = new QAction(description, videoDevicesGroup);
        videoDeviceAction->setCheckable(true);
        videoDeviceAction->setData(QVariant(deviceName));
        if (cameraDevice.isEmpty()) {
            cameraDevice = deviceName;
            videoDeviceAction->setChecked(true);
        }
        ui->menuDevices->addAction(videoDeviceAction);
    }

    connect(videoDevicesGroup, SIGNAL(triggered(QAction*)), this, SLOT(updateCameraDevice(QAction*)));
    connect(ui->captureWidget, SIGNAL(currentChanged(int)), SLOT(updateCaptureMode()));

#ifdef HAVE_CAMERA_BUTTONS
    ui->lockButton->hide();
#endif

    setCamera(cameraDevice);
}

Camera::~Camera()
{
    delete mediaRecorder;
    delete imageCapture;
    delete camera;
}

void Camera::setCamera(const QByteArray &cameraDevice)
{
    delete imageCapture;
    delete mediaRecorder;
    delete camera;

    if (cameraDevice.isEmpty())
        camera = new QCamera;
    else
        camera = new QCamera(cameraDevice);

    connect(camera, SIGNAL(stateChanged(QCamera::State)), this, SLOT(updateCameraState(QCamera::State)));
    connect(camera, SIGNAL(error(QCamera::Error)), this, SLOT(displayCameraError()));

    mediaRecorder = new QMediaRecorder(camera);
    connect(mediaRecorder, SIGNAL(stateChanged(QMediaRecorder::State)), this, SLOT(updateRecorderState(QMediaRecorder::State)));

    imageCapture = new QCameraImageCapture(camera);

    connect(mediaRecorder, SIGNAL(durationChanged(qint64)), this, SLOT(updateRecordTime()));
    connect(mediaRecorder, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(displayRecorderError()));

    mediaRecorder->setMetaData(QtMultimediaKit::Title, QVariant(QLatin1String("Test Title")));

    connect(ui->exposureCompensation, SIGNAL(valueChanged(int)), SLOT(setExposureCompensation(int)));

    camera->setViewfinder(ui->viewfinder);

    updateCameraState(camera->state());
    updateLockStatus(camera->lockStatus(), QCamera::UserRequest);
    updateRecorderState(mediaRecorder->state());

    connect(imageCapture, SIGNAL(readyForCaptureChanged(bool)), ui->takeImageButton, SLOT(setEnabled(bool)));
    connect(imageCapture, SIGNAL(imageCaptured(int,QImage)), this, SLOT(processCapturedImage(int,QImage)));

    connect(camera, SIGNAL(lockStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)),
            this, SLOT(updateLockStatus(QCamera::LockStatus, QCamera::LockChangeReason)));

    updateCaptureMode();
    camera->start();
}

void Camera::keyPressEvent(QKeyEvent * event)
{
    switch (event->key()) {
#if QT_VERSION >= 0x040700
    case Qt::Key_CameraFocus:
        camera->searchAndLock();
        break;
    case Qt::Key_Camera:
        if (camera->captureMode() == QCamera::CaptureStillImage)
            takeImage();
        else
            record();
        break;
#endif
    default:
        QMainWindow::keyPressEvent(event);
    }
}

void Camera::keyReleaseEvent(QKeyEvent * event)
{
    switch (event->key()) {
#if QT_VERSION >= 0x040700
    case Qt::Key_CameraFocus:
        camera->unlock();
        break;
    case Qt::Key_Camera:
        if (camera->captureMode() == QCamera::CaptureVideo)
            stop();
        break;
#endif
    default:
        QMainWindow::keyReleaseEvent(event);
    }
}

void Camera::updateRecordTime()
{
    QString str = QString("Recorded %1 sec").arg(mediaRecorder->duration()/1000);
    ui->statusbar->showMessage(str);
}

void Camera::processCapturedImage(int requestId, const QImage& img)
{
    Q_UNUSED(requestId);
    QImage scaledImage = img.scaled(ui->viewfinder->size(),
                                    Qt::KeepAspectRatio,
                                    Qt::SmoothTransformation);

    ui->lastImagePreviewLabel->setPixmap(QPixmap::fromImage(scaledImage));

    //display captured image for 4 seconds
    displayCapturedImage();
    QTimer::singleShot(4000, this, SLOT(displayViewfinder()));
}

void Camera::configureCaptureSettings()
{
    switch (camera->captureMode()) {
    case QCamera::CaptureStillImage:
        configureImageSettings();
        break;
    case QCamera::CaptureVideo:
        configureVideoSettings();
        break;
    default:
        break;
    }
}

void Camera::configureVideoSettings()
{
    VideoSettings settingsDialog(mediaRecorder);

    settingsDialog.setAudioSettings(audioSettings);
    settingsDialog.setVideoSettings(videoSettings);
    settingsDialog.setFormat(videoContainerFormat);

    if (settingsDialog.exec()) {
        audioSettings = settingsDialog.audioSettings();
        videoSettings = settingsDialog.videoSettings();
        videoContainerFormat = settingsDialog.format();

        mediaRecorder->setEncodingSettings(
                    audioSettings,
                    videoSettings,
                    videoContainerFormat);
    }
}

void Camera::configureImageSettings()
{
    ImageSettings settingsDialog(imageCapture);

    settingsDialog.setImageSettings(imageSettings);

    if (settingsDialog.exec()) {
        imageSettings = settingsDialog.imageSettings();
        imageCapture->setEncodingSettings(imageSettings);
    }
}

void Camera::record()
{
    mediaRecorder->record();
    updateRecordTime();
}

void Camera::pause()
{
    mediaRecorder->pause();
}

void Camera::stop()
{
    mediaRecorder->stop();
}

void Camera::setMuted(bool muted)
{
    mediaRecorder->setMuted(muted);
}

void Camera::toggleLock()
{
    switch (camera->lockStatus()) {
    case QCamera::Searching:
    case QCamera::Locked:
        camera->unlock();
        break;
    case QCamera::Unlocked:
        camera->searchAndLock();
    }
}

void Camera::updateLockStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason)
{
    QColor indicationColor = Qt::black;

    switch (status) {
    case QCamera::Searching:
        indicationColor = Qt::yellow;
        ui->statusbar->showMessage(tr("Focusing..."));
        ui->lockButton->setText(tr("Focusing..."));
        break;
    case QCamera::Locked:
        indicationColor = Qt::darkGreen;
        ui->lockButton->setText(tr("Unlock"));
        ui->statusbar->showMessage(tr("Focused"), 2000);
        break;
    case QCamera::Unlocked:
        indicationColor = reason == QCamera::LockFailed ? Qt::red : Qt::black;
        ui->lockButton->setText(tr("Focus"));
        if (reason == QCamera::LockFailed)
            ui->statusbar->showMessage(tr("Focus Failed"), 2000);
    }

    QPalette palette = ui->lockButton->palette();
    palette.setColor(QPalette::ButtonText, indicationColor);
    ui->lockButton->setPalette(palette);
}

void Camera::takeImage()
{
    imageCapture->capture();
}

void Camera::startCamera()
{
    camera->start();
}

void Camera::stopCamera()
{
    camera->stop();
}

void Camera::updateCaptureMode()
{
    int tabIndex = ui->captureWidget->currentIndex();
    QCamera::CaptureMode captureMode = tabIndex == 0 ? QCamera::CaptureStillImage : QCamera::CaptureVideo;
    camera->setCaptureMode(captureMode);
}

void Camera::updateCameraState(QCamera::State state)
{
    switch (state) {
    case QCamera::ActiveState:
        ui->actionStartCamera->setEnabled(false);
        ui->actionStopCamera->setEnabled(true);
        ui->captureWidget->setEnabled(true);
        ui->actionSettings->setEnabled(true);
        break;
    case QCamera::UnloadedState:
    case QCamera::LoadedState:
        ui->actionStartCamera->setEnabled(true);
        ui->actionStopCamera->setEnabled(false);
        ui->captureWidget->setEnabled(false);
        ui->actionSettings->setEnabled(false);
    }
}

void Camera::updateRecorderState(QMediaRecorder::State state)
{
    switch (state) {
    case QMediaRecorder::StoppedState:
        ui->recordButton->setEnabled(true);
        ui->pauseButton->setEnabled(true);
        ui->stopButton->setEnabled(false);
        break;
    case QMediaRecorder::PausedState:
        ui->recordButton->setEnabled(true);
        ui->pauseButton->setEnabled(false);
        ui->stopButton->setEnabled(true);
        break;
    case QMediaRecorder::RecordingState:
        ui->recordButton->setEnabled(false);
        ui->pauseButton->setEnabled(true);
        ui->stopButton->setEnabled(true);
        break;
    }
}

void Camera::setExposureCompensation(int index)
{
    camera->exposure()->setExposureCompensation(index*0.5);
}

void Camera::displayRecorderError()
{
    QMessageBox::warning(this, tr("Capture error"), mediaRecorder->errorString());
}

void Camera::displayCameraError()
{
    QMessageBox::warning(this, tr("Camera error"), camera->errorString());
}

void Camera::updateCameraDevice(QAction *action)
{
    setCamera(action->data().toByteArray());
}

void Camera::displayViewfinder()
{
    ui->stackedWidget->setCurrentIndex(0);
}

void Camera::displayCapturedImage()
{
    ui->stackedWidget->setCurrentIndex(1);
}
<commit_msg>Camera example: toggle recording when the camera button is pressed instead of recording while the button is pressed.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "camera.h"
#include "ui_camera.h"
#include "videosettings.h"
#include "imagesettings.h"

#include <qmediaservice.h>
#include <qmediarecorder.h>
#include <qcamera.h>
#include <qcameraviewfinder.h>

#include <qmessagebox.h>
#include <qpalette.h>

#include <QtGui>

#if (defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)) && QT_VERSION >= 0x040700
#define HAVE_CAMERA_BUTTONS
#endif

Camera::Camera(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Camera),
    camera(0),
    imageCapture(0),
    mediaRecorder(0)
{
    ui->setupUi(this);

    //Camera devices:
    QByteArray cameraDevice;

    QActionGroup *videoDevicesGroup = new QActionGroup(this);
    videoDevicesGroup->setExclusive(true);
    foreach(const QByteArray &deviceName, QCamera::availableDevices()) {
        QString description = camera->deviceDescription(deviceName);
        QAction *videoDeviceAction = new QAction(description, videoDevicesGroup);
        videoDeviceAction->setCheckable(true);
        videoDeviceAction->setData(QVariant(deviceName));
        if (cameraDevice.isEmpty()) {
            cameraDevice = deviceName;
            videoDeviceAction->setChecked(true);
        }
        ui->menuDevices->addAction(videoDeviceAction);
    }

    connect(videoDevicesGroup, SIGNAL(triggered(QAction*)), this, SLOT(updateCameraDevice(QAction*)));
    connect(ui->captureWidget, SIGNAL(currentChanged(int)), SLOT(updateCaptureMode()));

#ifdef HAVE_CAMERA_BUTTONS
    ui->lockButton->hide();
#endif

    setCamera(cameraDevice);
}

Camera::~Camera()
{
    delete mediaRecorder;
    delete imageCapture;
    delete camera;
}

void Camera::setCamera(const QByteArray &cameraDevice)
{
    delete imageCapture;
    delete mediaRecorder;
    delete camera;

    if (cameraDevice.isEmpty())
        camera = new QCamera;
    else
        camera = new QCamera(cameraDevice);

    connect(camera, SIGNAL(stateChanged(QCamera::State)), this, SLOT(updateCameraState(QCamera::State)));
    connect(camera, SIGNAL(error(QCamera::Error)), this, SLOT(displayCameraError()));

    mediaRecorder = new QMediaRecorder(camera);
    connect(mediaRecorder, SIGNAL(stateChanged(QMediaRecorder::State)), this, SLOT(updateRecorderState(QMediaRecorder::State)));

    imageCapture = new QCameraImageCapture(camera);

    connect(mediaRecorder, SIGNAL(durationChanged(qint64)), this, SLOT(updateRecordTime()));
    connect(mediaRecorder, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(displayRecorderError()));

    mediaRecorder->setMetaData(QtMultimediaKit::Title, QVariant(QLatin1String("Test Title")));

    connect(ui->exposureCompensation, SIGNAL(valueChanged(int)), SLOT(setExposureCompensation(int)));

    camera->setViewfinder(ui->viewfinder);

    updateCameraState(camera->state());
    updateLockStatus(camera->lockStatus(), QCamera::UserRequest);
    updateRecorderState(mediaRecorder->state());

    connect(imageCapture, SIGNAL(readyForCaptureChanged(bool)), ui->takeImageButton, SLOT(setEnabled(bool)));
    connect(imageCapture, SIGNAL(imageCaptured(int,QImage)), this, SLOT(processCapturedImage(int,QImage)));

    connect(camera, SIGNAL(lockStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)),
            this, SLOT(updateLockStatus(QCamera::LockStatus, QCamera::LockChangeReason)));

    updateCaptureMode();
    camera->start();
}

void Camera::keyPressEvent(QKeyEvent * event)
{
    switch (event->key()) {
#if QT_VERSION >= 0x040700
    case Qt::Key_CameraFocus:
        camera->searchAndLock();
        break;
    case Qt::Key_Camera:
        if (camera->captureMode() == QCamera::CaptureStillImage) {
            takeImage();
        } else {
            if (mediaRecorder->state() == QMediaRecorder::RecordingState)
                stop();
            else
                record();
        }
        break;
#endif
    default:
        QMainWindow::keyPressEvent(event);
    }
}

void Camera::keyReleaseEvent(QKeyEvent * event)
{
    switch (event->key()) {
#if QT_VERSION >= 0x040700
    case Qt::Key_CameraFocus:
        camera->unlock();
        break;
#endif
    default:
        QMainWindow::keyReleaseEvent(event);
    }
}

void Camera::updateRecordTime()
{
    QString str = QString("Recorded %1 sec").arg(mediaRecorder->duration()/1000);
    ui->statusbar->showMessage(str);
}

void Camera::processCapturedImage(int requestId, const QImage& img)
{
    Q_UNUSED(requestId);
    QImage scaledImage = img.scaled(ui->viewfinder->size(),
                                    Qt::KeepAspectRatio,
                                    Qt::SmoothTransformation);

    ui->lastImagePreviewLabel->setPixmap(QPixmap::fromImage(scaledImage));

    //display captured image for 4 seconds
    displayCapturedImage();
    QTimer::singleShot(4000, this, SLOT(displayViewfinder()));
}

void Camera::configureCaptureSettings()
{
    switch (camera->captureMode()) {
    case QCamera::CaptureStillImage:
        configureImageSettings();
        break;
    case QCamera::CaptureVideo:
        configureVideoSettings();
        break;
    default:
        break;
    }
}

void Camera::configureVideoSettings()
{
    VideoSettings settingsDialog(mediaRecorder);

    settingsDialog.setAudioSettings(audioSettings);
    settingsDialog.setVideoSettings(videoSettings);
    settingsDialog.setFormat(videoContainerFormat);

    if (settingsDialog.exec()) {
        audioSettings = settingsDialog.audioSettings();
        videoSettings = settingsDialog.videoSettings();
        videoContainerFormat = settingsDialog.format();

        mediaRecorder->setEncodingSettings(
                    audioSettings,
                    videoSettings,
                    videoContainerFormat);
    }
}

void Camera::configureImageSettings()
{
    ImageSettings settingsDialog(imageCapture);

    settingsDialog.setImageSettings(imageSettings);

    if (settingsDialog.exec()) {
        imageSettings = settingsDialog.imageSettings();
        imageCapture->setEncodingSettings(imageSettings);
    }
}

void Camera::record()
{
    mediaRecorder->record();
    updateRecordTime();
}

void Camera::pause()
{
    mediaRecorder->pause();
}

void Camera::stop()
{
    mediaRecorder->stop();
}

void Camera::setMuted(bool muted)
{
    mediaRecorder->setMuted(muted);
}

void Camera::toggleLock()
{
    switch (camera->lockStatus()) {
    case QCamera::Searching:
    case QCamera::Locked:
        camera->unlock();
        break;
    case QCamera::Unlocked:
        camera->searchAndLock();
    }
}

void Camera::updateLockStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason)
{
    QColor indicationColor = Qt::black;

    switch (status) {
    case QCamera::Searching:
        indicationColor = Qt::yellow;
        ui->statusbar->showMessage(tr("Focusing..."));
        ui->lockButton->setText(tr("Focusing..."));
        break;
    case QCamera::Locked:
        indicationColor = Qt::darkGreen;
        ui->lockButton->setText(tr("Unlock"));
        ui->statusbar->showMessage(tr("Focused"), 2000);
        break;
    case QCamera::Unlocked:
        indicationColor = reason == QCamera::LockFailed ? Qt::red : Qt::black;
        ui->lockButton->setText(tr("Focus"));
        if (reason == QCamera::LockFailed)
            ui->statusbar->showMessage(tr("Focus Failed"), 2000);
    }

    QPalette palette = ui->lockButton->palette();
    palette.setColor(QPalette::ButtonText, indicationColor);
    ui->lockButton->setPalette(palette);
}

void Camera::takeImage()
{
    imageCapture->capture();
}

void Camera::startCamera()
{
    camera->start();
}

void Camera::stopCamera()
{
    camera->stop();
}

void Camera::updateCaptureMode()
{
    int tabIndex = ui->captureWidget->currentIndex();
    QCamera::CaptureMode captureMode = tabIndex == 0 ? QCamera::CaptureStillImage : QCamera::CaptureVideo;
    camera->setCaptureMode(captureMode);
}

void Camera::updateCameraState(QCamera::State state)
{
    switch (state) {
    case QCamera::ActiveState:
        ui->actionStartCamera->setEnabled(false);
        ui->actionStopCamera->setEnabled(true);
        ui->captureWidget->setEnabled(true);
        ui->actionSettings->setEnabled(true);
        break;
    case QCamera::UnloadedState:
    case QCamera::LoadedState:
        ui->actionStartCamera->setEnabled(true);
        ui->actionStopCamera->setEnabled(false);
        ui->captureWidget->setEnabled(false);
        ui->actionSettings->setEnabled(false);
    }
}

void Camera::updateRecorderState(QMediaRecorder::State state)
{
    switch (state) {
    case QMediaRecorder::StoppedState:
        ui->recordButton->setEnabled(true);
        ui->pauseButton->setEnabled(true);
        ui->stopButton->setEnabled(false);
        break;
    case QMediaRecorder::PausedState:
        ui->recordButton->setEnabled(true);
        ui->pauseButton->setEnabled(false);
        ui->stopButton->setEnabled(true);
        break;
    case QMediaRecorder::RecordingState:
        ui->recordButton->setEnabled(false);
        ui->pauseButton->setEnabled(true);
        ui->stopButton->setEnabled(true);
        break;
    }
}

void Camera::setExposureCompensation(int index)
{
    camera->exposure()->setExposureCompensation(index*0.5);
}

void Camera::displayRecorderError()
{
    QMessageBox::warning(this, tr("Capture error"), mediaRecorder->errorString());
}

void Camera::displayCameraError()
{
    QMessageBox::warning(this, tr("Camera error"), camera->errorString());
}

void Camera::updateCameraDevice(QAction *action)
{
    setCamera(action->data().toByteArray());
}

void Camera::displayViewfinder()
{
    ui->stackedWidget->setCurrentIndex(0);
}

void Camera::displayCapturedImage()
{
    ui->stackedWidget->setCurrentIndex(1);
}
<|endoftext|>


<commit_before>// Copyright 2016 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 "gpu_surface_gl.h"

#if OS_IOS
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#elif OS_MACOSX
#include <OpenGL/gl3.h>
#else
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#endif

#include "flutter/glue/trace_event.h"
#include "lib/fxl/arraysize.h"
#include "lib/fxl/logging.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContextOptions.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"

namespace shell {

// Default maximum number of budgeted resources in the cache.
static const int kGrCacheMaxCount = 8192;

// Default maximum number of bytes of GPU memory of budgeted resources in the
// cache.
static const size_t kGrCacheMaxByteSize = 512 * (1 << 20);

GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate)
    : delegate_(delegate), weak_factory_(this) {
  if (!delegate_->GLContextMakeCurrent()) {
    FXL_LOG(ERROR)
        << "Could not make the context current to setup the gr context.";
    return;
  }

  GrContextOptions options;
  options.fAvoidStencilBuffers = true;

  auto context = GrContext::MakeGL(GrGLMakeNativeInterface(), options);

  if (context == nullptr) {
    FXL_LOG(ERROR) << "Failed to setup Skia Gr context.";
    return;
  }

  context_ = std::move(context);

  context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);

  delegate_->GLContextClearCurrent();

  valid_ = true;
}

GPUSurfaceGL::~GPUSurfaceGL() {
  if (!valid_) {
    return;
  }

  if (!delegate_->GLContextMakeCurrent()) {
    FXL_LOG(ERROR) << "Could not make the context current to destroy the "
                      "GrContext resources.";
    return;
  }

  onscreen_surface_ = nullptr;
  context_->releaseResourcesAndAbandonContext();
  context_ = nullptr;

  delegate_->GLContextClearCurrent();
}

bool GPUSurfaceGL::IsValid() {
  return valid_;
}

static SkColorType FirstSupportedColorType(GrContext* context, GLenum* format) {
#define RETURN_IF_RENDERABLE(x, y)                 \
  if (context->colorTypeSupportedAsSurface((x))) { \
    *format = (y);                                 \
    return (x);                                    \
  }
#if OS_MACOSX
  RETURN_IF_RENDERABLE(kRGBA_8888_SkColorType, GL_RGBA8);
#else
  RETURN_IF_RENDERABLE(kRGBA_8888_SkColorType, GL_RGBA8_OES);
#endif
  RETURN_IF_RENDERABLE(kARGB_4444_SkColorType, GL_RGBA4);
  RETURN_IF_RENDERABLE(kRGB_565_SkColorType, GL_RGB565);
  return kUnknown_SkColorType;
}

static sk_sp<SkSurface> WrapOnscreenSurface(GrContext* context,
                                            const SkISize& size,
                                            intptr_t fbo) {

  GLenum format;
  const SkColorType color_type = FirstSupportedColorType(context, &format);

  const GrGLFramebufferInfo framebuffer_info = {
      .fFBOID = static_cast<GrGLuint>(fbo),
      .fFormat = format,
  };

  GrBackendRenderTarget render_target(size.fWidth,      // width
                                      size.fHeight,     // height
                                      0,                // sample count
                                      0,                // stencil bits (TODO)
                                      framebuffer_info  // framebuffer info
  );

  sk_sp<SkColorSpace> colorspace = nullptr;

  SkSurfaceProps surface_props(
      SkSurfaceProps::InitType::kLegacyFontHost_InitType);

  return SkSurface::MakeFromBackendRenderTarget(
      context,                                       // gr context
      render_target,                                 // render target
      GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin,  // origin
      color_type,                                    // color type
      colorspace,                                    // colorspace
      &surface_props                                 // surface properties
  );
}

static sk_sp<SkSurface> CreateOffscreenSurface(GrContext* context,
                                               const SkISize& size) {
  const SkImageInfo image_info =
      SkImageInfo::MakeN32(size.fWidth, size.fHeight, kOpaque_SkAlphaType);

  const SkSurfaceProps surface_props(
      SkSurfaceProps::InitType::kLegacyFontHost_InitType);

  return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, image_info, 0,
                                     kBottomLeft_GrSurfaceOrigin,
                                     &surface_props);
}

bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
  if (onscreen_surface_ != nullptr &&
      size == SkISize::Make(onscreen_surface_->width(),
                            onscreen_surface_->height())) {
    // Surface size appears unchanged. So bail.
    return true;
  }

  // We need to do some updates.
  TRACE_EVENT0("flutter", "UpdateSurfacesSize");

  // Either way, we need to get rid of previous surface.
  onscreen_surface_ = nullptr;
  offscreen_surface_ = nullptr;

  if (size.isEmpty()) {
    FXL_LOG(ERROR) << "Cannot create surfaces of empty size.";
    return false;
  }

  sk_sp<SkSurface> onscreen_surface, offscreen_surface;

  onscreen_surface =
      WrapOnscreenSurface(context_.get(), size, delegate_->GLContextFBO());

  if (onscreen_surface == nullptr) {
    // If the onscreen surface could not be wrapped. There is absolutely no
    // point in moving forward.
    FXL_LOG(ERROR) << "Could not wrap onscreen surface.";
    return false;
  }

  if (delegate_->UseOffscreenSurface()) {
    offscreen_surface = CreateOffscreenSurface(context_.get(), size);
    if (offscreen_surface == nullptr) {
      FXL_LOG(ERROR) << "Could not create offscreen surface.";
      return false;
    }
  }

  onscreen_surface_ = std::move(onscreen_surface);
  offscreen_surface_ = std::move(offscreen_surface);

  return true;
}

std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
  if (delegate_ == nullptr) {
    return nullptr;
  }

  if (!delegate_->GLContextMakeCurrent()) {
    FXL_LOG(ERROR)
        << "Could not make the context current to acquire the frame.";
    return nullptr;
  }

  sk_sp<SkSurface> surface = AcquireRenderSurface(size);

  if (surface == nullptr) {
    return nullptr;
  }

  auto weak_this = weak_factory_.GetWeakPtr();

  SurfaceFrame::SubmitCallback submit_callback =
      [weak_this](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
        return weak_this ? weak_this->PresentSurface(canvas) : false;
      };

  return std::make_unique<SurfaceFrame>(surface, submit_callback);
}

bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
  if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) {
    return false;
  }

  if (offscreen_surface_ != nullptr) {
    TRACE_EVENT0("flutter", "CopyTextureOnscreen");
    SkPaint paint;
    onscreen_surface_->getCanvas()->drawImage(
        offscreen_surface_->makeImageSnapshot(), 0, 0, &paint);
  }

  {
    TRACE_EVENT0("flutter", "SkCanvas::Flush");
    onscreen_surface_->getCanvas()->flush();
  }

  delegate_->GLContextPresent();

  return true;
}

sk_sp<SkSurface> GPUSurfaceGL::AcquireRenderSurface(const SkISize& size) {
  if (!CreateOrUpdateSurfaces(size)) {
    return nullptr;
  }

  return offscreen_surface_ != nullptr ? offscreen_surface_ : onscreen_surface_;
}

GrContext* GPUSurfaceGL::GetContext() {
  return context_.get();
}

}  // namespace shell
<commit_msg>Fix supported color type check on iOS simulators (#4846)<commit_after>// Copyright 2016 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 "gpu_surface_gl.h"

#if OS_IOS
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#elif OS_MACOSX
#include <OpenGL/gl3.h>
#else
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#endif

#include "flutter/glue/trace_event.h"
#include "lib/fxl/arraysize.h"
#include "lib/fxl/logging.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContextOptions.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"

namespace shell {

// Default maximum number of budgeted resources in the cache.
static const int kGrCacheMaxCount = 8192;

// Default maximum number of bytes of GPU memory of budgeted resources in the
// cache.
static const size_t kGrCacheMaxByteSize = 512 * (1 << 20);

GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate)
    : delegate_(delegate), weak_factory_(this) {
  if (!delegate_->GLContextMakeCurrent()) {
    FXL_LOG(ERROR)
        << "Could not make the context current to setup the gr context.";
    return;
  }

  GrContextOptions options;
  options.fAvoidStencilBuffers = true;

  auto context = GrContext::MakeGL(GrGLMakeNativeInterface(), options);

  if (context == nullptr) {
    FXL_LOG(ERROR) << "Failed to setup Skia Gr context.";
    return;
  }

  context_ = std::move(context);

  context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);

  delegate_->GLContextClearCurrent();

  valid_ = true;
}

GPUSurfaceGL::~GPUSurfaceGL() {
  if (!valid_) {
    return;
  }

  if (!delegate_->GLContextMakeCurrent()) {
    FXL_LOG(ERROR) << "Could not make the context current to destroy the "
                      "GrContext resources.";
    return;
  }

  onscreen_surface_ = nullptr;
  context_->releaseResourcesAndAbandonContext();
  context_ = nullptr;

  delegate_->GLContextClearCurrent();
}

bool GPUSurfaceGL::IsValid() {
  return valid_;
}

static SkColorType FirstSupportedColorType(GrContext* context, GLenum* format) {
#define RETURN_IF_RENDERABLE(x, y)                 \
  if (context->colorTypeSupportedAsSurface((x))) { \
    *format = (y);                                 \
    return (x);                                    \
  }
#if OS_MACOSX && !OS_IOS
  RETURN_IF_RENDERABLE(kRGBA_8888_SkColorType, GL_RGBA8);
#else
  RETURN_IF_RENDERABLE(kRGBA_8888_SkColorType, GL_RGBA8_OES);
#endif
  RETURN_IF_RENDERABLE(kARGB_4444_SkColorType, GL_RGBA4);
  RETURN_IF_RENDERABLE(kRGB_565_SkColorType, GL_RGB565);
  return kUnknown_SkColorType;
}

static sk_sp<SkSurface> WrapOnscreenSurface(GrContext* context,
                                            const SkISize& size,
                                            intptr_t fbo) {

  GLenum format;
  const SkColorType color_type = FirstSupportedColorType(context, &format);

  const GrGLFramebufferInfo framebuffer_info = {
      .fFBOID = static_cast<GrGLuint>(fbo),
      .fFormat = format,
  };

  GrBackendRenderTarget render_target(size.fWidth,      // width
                                      size.fHeight,     // height
                                      0,                // sample count
                                      0,                // stencil bits (TODO)
                                      framebuffer_info  // framebuffer info
  );

  sk_sp<SkColorSpace> colorspace = nullptr;

  SkSurfaceProps surface_props(
      SkSurfaceProps::InitType::kLegacyFontHost_InitType);

  return SkSurface::MakeFromBackendRenderTarget(
      context,                                       // gr context
      render_target,                                 // render target
      GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin,  // origin
      color_type,                                    // color type
      colorspace,                                    // colorspace
      &surface_props                                 // surface properties
  );
}

static sk_sp<SkSurface> CreateOffscreenSurface(GrContext* context,
                                               const SkISize& size) {
  const SkImageInfo image_info =
      SkImageInfo::MakeN32(size.fWidth, size.fHeight, kOpaque_SkAlphaType);

  const SkSurfaceProps surface_props(
      SkSurfaceProps::InitType::kLegacyFontHost_InitType);

  return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, image_info, 0,
                                     kBottomLeft_GrSurfaceOrigin,
                                     &surface_props);
}

bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
  if (onscreen_surface_ != nullptr &&
      size == SkISize::Make(onscreen_surface_->width(),
                            onscreen_surface_->height())) {
    // Surface size appears unchanged. So bail.
    return true;
  }

  // We need to do some updates.
  TRACE_EVENT0("flutter", "UpdateSurfacesSize");

  // Either way, we need to get rid of previous surface.
  onscreen_surface_ = nullptr;
  offscreen_surface_ = nullptr;

  if (size.isEmpty()) {
    FXL_LOG(ERROR) << "Cannot create surfaces of empty size.";
    return false;
  }

  sk_sp<SkSurface> onscreen_surface, offscreen_surface;

  onscreen_surface =
      WrapOnscreenSurface(context_.get(), size, delegate_->GLContextFBO());

  if (onscreen_surface == nullptr) {
    // If the onscreen surface could not be wrapped. There is absolutely no
    // point in moving forward.
    FXL_LOG(ERROR) << "Could not wrap onscreen surface.";
    return false;
  }

  if (delegate_->UseOffscreenSurface()) {
    offscreen_surface = CreateOffscreenSurface(context_.get(), size);
    if (offscreen_surface == nullptr) {
      FXL_LOG(ERROR) << "Could not create offscreen surface.";
      return false;
    }
  }

  onscreen_surface_ = std::move(onscreen_surface);
  offscreen_surface_ = std::move(offscreen_surface);

  return true;
}

std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
  if (delegate_ == nullptr) {
    return nullptr;
  }

  if (!delegate_->GLContextMakeCurrent()) {
    FXL_LOG(ERROR)
        << "Could not make the context current to acquire the frame.";
    return nullptr;
  }

  sk_sp<SkSurface> surface = AcquireRenderSurface(size);

  if (surface == nullptr) {
    return nullptr;
  }

  auto weak_this = weak_factory_.GetWeakPtr();

  SurfaceFrame::SubmitCallback submit_callback =
      [weak_this](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
        return weak_this ? weak_this->PresentSurface(canvas) : false;
      };

  return std::make_unique<SurfaceFrame>(surface, submit_callback);
}

bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
  if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) {
    return false;
  }

  if (offscreen_surface_ != nullptr) {
    TRACE_EVENT0("flutter", "CopyTextureOnscreen");
    SkPaint paint;
    onscreen_surface_->getCanvas()->drawImage(
        offscreen_surface_->makeImageSnapshot(), 0, 0, &paint);
  }

  {
    TRACE_EVENT0("flutter", "SkCanvas::Flush");
    onscreen_surface_->getCanvas()->flush();
  }

  delegate_->GLContextPresent();

  return true;
}

sk_sp<SkSurface> GPUSurfaceGL::AcquireRenderSurface(const SkISize& size) {
  if (!CreateOrUpdateSurfaces(size)) {
    return nullptr;
  }

  return offscreen_surface_ != nullptr ? offscreen_surface_ : onscreen_surface_;
}

GrContext* GPUSurfaceGL::GetContext() {
  return context_.get();
}

}  // namespace shell
<|endoftext|>


<commit_before>/*
 * Copyright 2003,2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id$
 */

#include <xercesc/framework/psvi/XSIDCDefinition.hpp>
#include <xercesc/validators/schema/identity/IC_KeyRef.hpp>
#include <xercesc/validators/schema/identity/IC_Selector.hpp>
#include <xercesc/validators/schema/identity/XercesXPath.hpp>
#include <xercesc/framework/psvi/XSModel.hpp>
#include <xercesc/framework/psvi/XSAnnotation.hpp>
#include <xercesc/util/StringPool.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  XSIDCDefinition: Constructors and Destructor
// ---------------------------------------------------------------------------
XSIDCDefinition::XSIDCDefinition(IdentityConstraint* const identityConstraint,
                                 XSIDCDefinition*  const   keyIC,
                                 XSAnnotation* const       headAnnot,
                                 StringList* const         stringList,
                                 XSModel* const            xsModel,
                                 MemoryManager* const      manager)
    : XSObject(XSConstants::IDENTITY_CONSTRAINT, xsModel, manager)
    , fIdentityConstraint(identityConstraint)
    , fKey(keyIC)
    , fStringList(stringList)
    , fXSAnnotationList(0)
{
    if (headAnnot)
    {
        fXSAnnotationList = new (manager) RefVectorOf<XSAnnotation>(1, false, manager);

        XSAnnotation* annot = headAnnot;
        do
        {
            fXSAnnotationList->addElement(annot);
            annot = annot->getNext();
        } while (annot);
    }

}

XSIDCDefinition::~XSIDCDefinition()
{
    if (fStringList)
        delete fStringList;

    // don't delete fKey - deleted by XSModel
    if (fXSAnnotationList)
        delete fXSAnnotationList;
}

// ---------------------------------------------------------------------------
//  XSIDCDefinition: XSObject virtual methods
// ---------------------------------------------------------------------------
const XMLCh *XSIDCDefinition::getName()
{
    return fIdentityConstraint->getIdentityConstraintName();
}

const XMLCh *XSIDCDefinition::getNamespace()
{
    return fXSModel->getURIStringPool()->getValueForId(fIdentityConstraint->getNamespaceURI());
}

XSNamespaceItem *XSIDCDefinition::getNamespaceItem()
{
    return fXSModel->getNamespaceItem(getNamespace());
}

// ---------------------------------------------------------------------------
//  XSIDCDefinition: access methods
// ---------------------------------------------------------------------------
XSIDCDefinition::IC_CATEGORY XSIDCDefinition::getCategory() const
{
    switch(fIdentityConstraint->getType()) {
        case IdentityConstraint::UNIQUE:
            return IC_UNIQUE;
        case IdentityConstraint::KEY:
            return IC_KEY;
        case IdentityConstraint::KEYREF:
            return IC_KEYREF;
        default:
            // REVISIT:
            // should never really get here... IdentityConstraint::Unknown is the other
            // choice so need a default case for completeness; should issues error?
            return IC_KEY;
    }
}

const XMLCh *XSIDCDefinition::getSelectorStr()
{
    return fIdentityConstraint->getSelector()->getXPath()->getExpression();
}

XSAnnotationList *XSIDCDefinition::getAnnotations()
{
    return fXSAnnotationList;
}

XERCES_CPP_NAMESPACE_END

<commit_msg>Change uppercase enums that were conflicting with other products.<commit_after>/*
 * Copyright 2003,2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id$
 */

#include <xercesc/framework/psvi/XSIDCDefinition.hpp>
#include <xercesc/validators/schema/identity/IC_KeyRef.hpp>
#include <xercesc/validators/schema/identity/IC_Selector.hpp>
#include <xercesc/validators/schema/identity/XercesXPath.hpp>
#include <xercesc/framework/psvi/XSModel.hpp>
#include <xercesc/framework/psvi/XSAnnotation.hpp>
#include <xercesc/util/StringPool.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  XSIDCDefinition: Constructors and Destructor
// ---------------------------------------------------------------------------
XSIDCDefinition::XSIDCDefinition(IdentityConstraint* const identityConstraint,
                                 XSIDCDefinition*  const   keyIC,
                                 XSAnnotation* const       headAnnot,
                                 StringList* const         stringList,
                                 XSModel* const            xsModel,
                                 MemoryManager* const      manager)
    : XSObject(XSConstants::IDENTITY_CONSTRAINT, xsModel, manager)
    , fIdentityConstraint(identityConstraint)
    , fKey(keyIC)
    , fStringList(stringList)
    , fXSAnnotationList(0)
{
    if (headAnnot)
    {
        fXSAnnotationList = new (manager) RefVectorOf<XSAnnotation>(1, false, manager);

        XSAnnotation* annot = headAnnot;
        do
        {
            fXSAnnotationList->addElement(annot);
            annot = annot->getNext();
        } while (annot);
    }

}

XSIDCDefinition::~XSIDCDefinition()
{
    if (fStringList)
        delete fStringList;

    // don't delete fKey - deleted by XSModel
    if (fXSAnnotationList)
        delete fXSAnnotationList;
}

// ---------------------------------------------------------------------------
//  XSIDCDefinition: XSObject virtual methods
// ---------------------------------------------------------------------------
const XMLCh *XSIDCDefinition::getName()
{
    return fIdentityConstraint->getIdentityConstraintName();
}

const XMLCh *XSIDCDefinition::getNamespace()
{
    return fXSModel->getURIStringPool()->getValueForId(fIdentityConstraint->getNamespaceURI());
}

XSNamespaceItem *XSIDCDefinition::getNamespaceItem()
{
    return fXSModel->getNamespaceItem(getNamespace());
}

// ---------------------------------------------------------------------------
//  XSIDCDefinition: access methods
// ---------------------------------------------------------------------------
XSIDCDefinition::IC_CATEGORY XSIDCDefinition::getCategory() const
{
    switch(fIdentityConstraint->getType()) {
        case IdentityConstraint::ICType_UNIQUE:
            return IC_UNIQUE;
        case IdentityConstraint::ICType_KEY:
            return IC_KEY;
        case IdentityConstraint::ICType_KEYREF:
            return IC_KEYREF;
        default:
            // REVISIT:
            // should never really get here... IdentityConstraint::Unknown is the other
            // choice so need a default case for completeness; should issues error?
            return IC_KEY;
    }
}

const XMLCh *XSIDCDefinition::getSelectorStr()
{
    return fIdentityConstraint->getSelector()->getXPath()->getExpression();
}

XSAnnotationList *XSIDCDefinition::getAnnotations()
{
    return fXSAnnotationList;
}

XERCES_CPP_NAMESPACE_END

<|endoftext|>


<commit_before>#include <sstream>
#include <limits>

#include <debug.h>

#include <thrift/transport/TTransportException.h>

#include "thrift_line/TalkService.h"

#include "constants.hpp"
#include "linehttptransport.hpp"

LineHttpTransport::LineHttpTransport(
        PurpleAccount *acct,
        PurpleConnection *conn,
        std::string host,
        uint16_t port,
        bool ls_mode) :
    acct(acct),
    conn(conn),
    host(host),
    port(port),
    ls_mode(ls_mode),
    auth_token(""),
    state(ConnectionState::DISCONNECTED),
    auto_reconnect(false),
    reconnect_timeout_handle(0),
    reconnect_timeout(0),
    ssl(NULL),
    input_handle(0),
    connection_id(0),
    request_written(0),
    keep_alive(false),
    status_code_(0),
    content_length_(0)
{
}

LineHttpTransport::~LineHttpTransport() {
    close();
}

void LineHttpTransport::set_auto_reconnect(bool auto_reconnect) {
    if (state == ConnectionState::DISCONNECTED)
        this->auto_reconnect = auto_reconnect;
}

void LineHttpTransport::set_auth_token(std::string token) {
    this->auth_token = token;
}

int LineHttpTransport::status_code() {
    return status_code_;
}

int LineHttpTransport::content_length() {
    return content_length_;
}

void LineHttpTransport::open() {
    if (state != ConnectionState::DISCONNECTED)
        return;

    state = ConnectionState::CONNECTED;

    in_progress = false;

    connection_id++;
    ssl = purple_ssl_connect(
        acct,
        host.c_str(),
        port,
        WRAPPER(LineHttpTransport::ssl_connect),
        WRAPPER_TYPE(LineHttpTransport::ssl_error, end),
        (gpointer)this);
}

void LineHttpTransport::ssl_connect(PurpleSslConnection *, PurpleInputCondition) {
    reconnect_timeout = 0;

    send_next();
}

void LineHttpTransport::ssl_error(PurpleSslConnection *, PurpleSslErrorType err) {
    purple_debug_warning("line", "SSL error: %s\n", purple_ssl_strerror(err));

    ssl = nullptr;

    purple_connection_ssl_error(conn, err);
}

void LineHttpTransport::close() {
    if (state == ConnectionState::DISCONNECTED)
        return;

    state = ConnectionState::DISCONNECTED;

    if (reconnect_timeout_handle) {
        purple_timeout_remove(reconnect_timeout_handle);
        reconnect_timeout_handle = 0;
    }

    if (input_handle) {
        purple_input_remove(input_handle);
        input_handle = 0;
    }

    purple_ssl_close(ssl);
    ssl = NULL;
    connection_id++;

    x_ls = "";

    request_buf.str("");

    response_str = "";
    response_buf.str("");
}

uint32_t LineHttpTransport::read_virt(uint8_t *buf, uint32_t len) {
    return (uint32_t )response_buf.sgetn((char *)buf, len);
}

void LineHttpTransport::write_virt(const uint8_t *buf, uint32_t len) {
    request_buf.sputn((const char *)buf, len);
}

void LineHttpTransport::request(std::string method, std::string path, std::string content_type,
    std::function<void()> callback)
{
    Request req;
    req.method = method;
    req.path = path;
    req.content_type = content_type;
    req.body = request_buf.str();
    req.callback = callback;
    request_queue.push(req);

    request_buf.str("");

    send_next();
}

void LineHttpTransport::send_next() {
    if (state != ConnectionState::CONNECTED) {
        open();
        return;
    }

    if (in_progress || request_queue.empty())
        return;

    keep_alive = false;
    status_code_ = -1;
    content_length_ = -1;

    Request &next_req = request_queue.front();

    std::ostringstream data;

    data
        << next_req.method << " " << next_req.path << " HTTP/1.1" "\r\n";

    if (ls_mode && x_ls != "") {
        data << "X-LS: " << x_ls << "\r\n";
    } else {
        data
            << "Connection: Keep-Alive\r\n"
            << "Content-Type: " << next_req.content_type << "\r\n"
            << "Host: " << host << ":" << port << "\r\n"
            << "User-Agent: " LINE_USER_AGENT "\r\n"
            << "X-Line-Application: " LINE_APPLICATION "\r\n";

        if (auth_token != "")
            data << "X-Line-Access: " << auth_token << "\r\n";
    }

    if (next_req.method == "POST")
        data << "Content-Length: " << next_req.body.size() << "\r\n";

    data
        << "\r\n"
        << next_req.body;

    request_data = data.str();
    request_written = 0;
    in_progress = true;

    input_handle = purple_input_add(ssl->fd, PURPLE_INPUT_WRITE,
        WRAPPER(LineHttpTransport::ssl_write), (gpointer)this);
    ssl_write(ssl->fd, PURPLE_INPUT_WRITE);
}

int LineHttpTransport::reconnect_timeout_cb() {
    reconnect_timeout = reconnect_timeout ? 10 : 60;

    state = ConnectionState::DISCONNECTED;

    open();

    return FALSE;
}

void LineHttpTransport::write_request() {
    if (request_written < request_data.size()) {
        size_t r = purple_ssl_write(ssl,
            request_data.c_str() + request_written, request_data.size() - request_written);

        request_written += r;

        purple_debug_info("line", "Wrote: %d, %d out of %d!\n",
                (int)r, (int)request_written, (int)request_data.size());
    }
}

void LineHttpTransport::ssl_write(gint, PurpleInputCondition) {
    if (state != ConnectionState::CONNECTED) {
        if (input_handle) {
            purple_input_remove(input_handle);
            input_handle = 0;
        }

        return;
    }

    if (request_written < request_data.size()) {
        request_written += purple_ssl_write(ssl,
            request_data.c_str() + request_written, request_data.size() - request_written);
    }

    if (request_written >= request_data.size()) {
        purple_input_remove(input_handle);

        input_handle = purple_input_add(ssl->fd, PURPLE_INPUT_READ,
            WRAPPER(LineHttpTransport::ssl_read), (gpointer)this);
    }
}

void LineHttpTransport::ssl_read(gint, PurpleInputCondition) {
    if (state != ConnectionState::CONNECTED) {
        purple_input_remove(input_handle);
        input_handle = 0;
        return;
    }

    bool any = false;

    while (true) {
        size_t count = purple_ssl_read(ssl, (void *)buf, BUFFER_SIZE);

        if (count == 0) {
            if (any)
                break;

            purple_debug_info("line", "Connection lost.\n");

            close();

            if (in_progress) {
                if (auto_reconnect) {
                    purple_debug_info("line", "Reconnecting in %ds...\n",
                        reconnect_timeout);

                    state = ConnectionState::RECONNECTING;

                    purple_timeout_add_seconds(
                        reconnect_timeout,
                        WRAPPER(LineHttpTransport::reconnect_timeout_cb),
                        (gpointer)this);
                } else {
                    conn->wants_to_die = TRUE;
                    purple_connection_error(conn, "LINE: Could not connect to server.");
                }
            }

            return;
        }

        if (count == (size_t)-1)
            break;

        any = true;

        response_str.append((const char *)buf, count);

        try_parse_response_header();

        if (content_length_ >= 0 && response_str.size() >= (size_t)content_length_) {
            purple_input_remove(input_handle);

            if (status_code_ == 403) {
                // Don't try to reconnect because this usually means the user has logged in from
                // elsewhere.

                // TODO: Check actual reason

                conn->wants_to_die = TRUE;
                purple_connection_error(conn, "Session died.");
                return;
            }

            response_buf.str(response_str.substr(0, content_length_));
            response_str.erase(0, content_length_);

            int connection_id_before = connection_id;

            try {
                request_queue.front().callback();
            } catch (line::TalkException &err) {
                std::string msg = "LINE: TalkException: ";
                msg += err.reason;

                if (err.code == line::ErrorCode::NOT_AUTHORIZED_DEVICE) {
                    purple_account_remove_setting(acct, LINE_ACCOUNT_AUTH_TOKEN);

                    if (err.reason == "AUTHENTICATION_DIVESTED_BY_OTHER_DEVICE") {
                        msg = "LINE: You have been logged out because "
                            "you logged in from another device.";
                    } else if (err.reason == "REVOKE") {
                        msg = "LINE: This device was logged out via the mobile app.";
                    }
                }

                conn->wants_to_die = TRUE;
                purple_connection_error(conn, msg.c_str());
                return;
            } catch (apache::thrift::TApplicationException &err) {
                std::string msg = "LINE: Application error: ";
                msg += err.what();

                conn->wants_to_die = TRUE;
                purple_connection_error(conn, msg.c_str());
                return;
            } catch (apache::thrift::transport::TTransportException &err) {
                std::string msg = "LINE: Transport error: ";
                msg += err.what();

                conn->wants_to_die = TRUE;
                purple_connection_error(conn, msg.c_str());
                return;
            }

            request_queue.pop();

            in_progress = false;

            if (connection_id != connection_id_before)
                break; // Callback closed connection, don't try to continue reading

            if (!keep_alive) {
                close();
                send_next();
                break;
            }

            send_next();
        }
    }
}

void LineHttpTransport::try_parse_response_header() {
    size_t header_end = response_str.find("\r\n\r\n");
    if (header_end == std::string::npos)
        return;

    std::istringstream stream(response_str.substr(0, header_end));

    stream.ignore(256, ' ');
    stream >> status_code_;
    stream.ignore(256, '\n');

    while (stream) {
        std::string name, value;

        std::getline(stream, name, ':');
        stream.ignore(256, ' ');

        if (name == "Content-Length")
            stream >> content_length_;

        if (name == "X-LS")
            std::getline(stream, x_ls, '\r');

        if (name == "Connection") {
            std::string value;
            std::getline(stream, value, '\r');

            if (value == "Keep-Alive" || value == "Keep-alive" || value == "keep-alive")
                keep_alive = true;
        }

        stream.ignore(256, '\n');
    }

    response_str.erase(0, header_end + 4);
}
<commit_msg>Reconnect automatically in more error situations.<commit_after>#include <sstream>
#include <limits>

#include <debug.h>

#include <thrift/transport/TTransportException.h>

#include "thrift_line/TalkService.h"

#include "constants.hpp"
#include "linehttptransport.hpp"

LineHttpTransport::LineHttpTransport(
        PurpleAccount *acct,
        PurpleConnection *conn,
        std::string host,
        uint16_t port,
        bool ls_mode) :
    acct(acct),
    conn(conn),
    host(host),
    port(port),
    ls_mode(ls_mode),
    auth_token(""),
    state(ConnectionState::DISCONNECTED),
    auto_reconnect(false),
    reconnect_timeout_handle(0),
    reconnect_timeout(0),
    ssl(NULL),
    input_handle(0),
    connection_id(0),
    request_written(0),
    keep_alive(false),
    status_code_(0),
    content_length_(0)
{
}

LineHttpTransport::~LineHttpTransport() {
    close();
}

void LineHttpTransport::set_auto_reconnect(bool auto_reconnect) {
    if (state == ConnectionState::DISCONNECTED)
        this->auto_reconnect = auto_reconnect;
}

void LineHttpTransport::set_auth_token(std::string token) {
    this->auth_token = token;
}

int LineHttpTransport::status_code() {
    return status_code_;
}

int LineHttpTransport::content_length() {
    return content_length_;
}

void LineHttpTransport::open() {
    if (state != ConnectionState::DISCONNECTED)
        return;

    state = ConnectionState::CONNECTED;

    in_progress = false;

    connection_id++;
    ssl = purple_ssl_connect(
        acct,
        host.c_str(),
        port,
        WRAPPER(LineHttpTransport::ssl_connect),
        WRAPPER_TYPE(LineHttpTransport::ssl_error, end),
        (gpointer)this);
}

void LineHttpTransport::ssl_connect(PurpleSslConnection *, PurpleInputCondition) {
    reconnect_timeout = 0;

    send_next();
}

void LineHttpTransport::ssl_error(PurpleSslConnection *, PurpleSslErrorType err) {
    purple_debug_warning("line", "SSL error: %s\n", purple_ssl_strerror(err));

    ssl = nullptr;

    purple_connection_ssl_error(conn, err);
}

void LineHttpTransport::close() {
    if (state == ConnectionState::DISCONNECTED)
        return;

    state = ConnectionState::DISCONNECTED;

    if (reconnect_timeout_handle) {
        purple_timeout_remove(reconnect_timeout_handle);
        reconnect_timeout_handle = 0;
    }

    if (input_handle) {
        purple_input_remove(input_handle);
        input_handle = 0;
    }

    purple_ssl_close(ssl);
    ssl = NULL;
    connection_id++;

    x_ls = "";

    request_buf.str("");

    response_str = "";
    response_buf.str("");
}

uint32_t LineHttpTransport::read_virt(uint8_t *buf, uint32_t len) {
    return (uint32_t )response_buf.sgetn((char *)buf, len);
}

void LineHttpTransport::write_virt(const uint8_t *buf, uint32_t len) {
    request_buf.sputn((const char *)buf, len);
}

void LineHttpTransport::request(std::string method, std::string path, std::string content_type,
    std::function<void()> callback)
{
    Request req;
    req.method = method;
    req.path = path;
    req.content_type = content_type;
    req.body = request_buf.str();
    req.callback = callback;
    request_queue.push(req);

    request_buf.str("");

    send_next();
}

void LineHttpTransport::send_next() {
    if (state != ConnectionState::CONNECTED) {
        open();
        return;
    }

    if (in_progress || request_queue.empty())
        return;

    keep_alive = false;
    status_code_ = -1;
    content_length_ = -1;

    Request &next_req = request_queue.front();

    std::ostringstream data;

    data
        << next_req.method << " " << next_req.path << " HTTP/1.1" "\r\n";

    if (ls_mode && x_ls != "") {
        data << "X-LS: " << x_ls << "\r\n";
    } else {
        data
            << "Connection: Keep-Alive\r\n"
            << "Content-Type: " << next_req.content_type << "\r\n"
            << "Host: " << host << ":" << port << "\r\n"
            << "User-Agent: " LINE_USER_AGENT "\r\n"
            << "X-Line-Application: " LINE_APPLICATION "\r\n";

        if (auth_token != "")
            data << "X-Line-Access: " << auth_token << "\r\n";
    }

    if (next_req.method == "POST")
        data << "Content-Length: " << next_req.body.size() << "\r\n";

    data
        << "\r\n"
        << next_req.body;

    request_data = data.str();
    request_written = 0;
    in_progress = true;

    input_handle = purple_input_add(ssl->fd, PURPLE_INPUT_WRITE,
        WRAPPER(LineHttpTransport::ssl_write), (gpointer)this);
    ssl_write(ssl->fd, PURPLE_INPUT_WRITE);
}

int LineHttpTransport::reconnect_timeout_cb() {
    reconnect_timeout = reconnect_timeout ? 10 : 60;

    state = ConnectionState::DISCONNECTED;

    open();

    return FALSE;
}

void LineHttpTransport::write_request() {
    if (request_written < request_data.size()) {
        size_t r = purple_ssl_write(ssl,
            request_data.c_str() + request_written, request_data.size() - request_written);

        request_written += r;

        purple_debug_info("line", "Wrote: %d, %d out of %d!\n",
                (int)r, (int)request_written, (int)request_data.size());
    }
}

void LineHttpTransport::ssl_write(gint, PurpleInputCondition) {
    if (state != ConnectionState::CONNECTED) {
        if (input_handle) {
            purple_input_remove(input_handle);
            input_handle = 0;
        }

        return;
    }

    if (request_written < request_data.size()) {
        request_written += purple_ssl_write(ssl,
            request_data.c_str() + request_written, request_data.size() - request_written);
    }

    if (request_written >= request_data.size()) {
        purple_input_remove(input_handle);

        input_handle = purple_input_add(ssl->fd, PURPLE_INPUT_READ,
            WRAPPER(LineHttpTransport::ssl_read), (gpointer)this);
    }
}

void LineHttpTransport::ssl_read(gint, PurpleInputCondition) {
    if (state != ConnectionState::CONNECTED) {
        purple_input_remove(input_handle);
        input_handle = 0;
        return;
    }

    bool any = false;

    while (true) {
        size_t count = purple_ssl_read(ssl, (void *)buf, BUFFER_SIZE);

        if (count == 0) {
            if (any)
                break;

            purple_debug_info("line", "Connection lost.\n");

            close();

            if (in_progress) {
                if (auto_reconnect) {
                    purple_debug_info("line", "Reconnecting in %ds...\n",
                        reconnect_timeout);

                    state = ConnectionState::RECONNECTING;

                    purple_timeout_add_seconds(
                        reconnect_timeout,
                        WRAPPER(LineHttpTransport::reconnect_timeout_cb),
                        (gpointer)this);
                } else {
                    conn->wants_to_die = TRUE;
                    purple_connection_error(conn, "LINE: Could not connect to server.");
                }
            }

            return;
        }

        if (count == (size_t)-1)
            break;

        any = true;

        response_str.append((const char *)buf, count);

        try_parse_response_header();

        if (content_length_ >= 0 && response_str.size() >= (size_t)content_length_) {
            purple_input_remove(input_handle);

            if (status_code_ == 403) {
                // Don't try to reconnect because this usually means the user has logged in from
                // elsewhere.

                // TODO: Check actual reason

                conn->wants_to_die = TRUE;
                purple_connection_error(conn, "Session died.");
                return;
            }

            response_buf.str(response_str.substr(0, content_length_));
            response_str.erase(0, content_length_);

            int connection_id_before = connection_id;

            try {
                request_queue.front().callback();
            } catch (line::TalkException &err) {
                std::string msg = "LINE: TalkException: ";
                msg += err.reason;

                if (err.code == line::ErrorCode::NOT_AUTHORIZED_DEVICE) {
                    purple_account_remove_setting(acct, LINE_ACCOUNT_AUTH_TOKEN);

                    if (err.reason == "AUTHENTICATION_DIVESTED_BY_OTHER_DEVICE") {
                        msg = "LINE: You have been logged out because "
                            "you logged in from another device.";
                    } else if (err.reason == "REVOKE") {
                        msg = "LINE: This device was logged out via the mobile app.";
                    }

                    conn->wants_to_die = TRUE;
                }

                purple_connection_error(conn, msg.c_str());
                return;
            } catch (apache::thrift::TApplicationException &err) {
                std::string msg = "LINE: Application error: ";
                msg += err.what();

                purple_connection_error(conn, msg.c_str());
                return;
            } catch (apache::thrift::transport::TTransportException &err) {
                std::string msg = "LINE: Transport error: ";
                msg += err.what();

                purple_connection_error(conn, msg.c_str());
                return;
            }

            request_queue.pop();

            in_progress = false;

            if (connection_id != connection_id_before)
                break; // Callback closed connection, don't try to continue reading

            if (!keep_alive) {
                close();
                send_next();
                break;
            }

            send_next();
        }
    }
}

void LineHttpTransport::try_parse_response_header() {
    size_t header_end = response_str.find("\r\n\r\n");
    if (header_end == std::string::npos)
        return;

    std::istringstream stream(response_str.substr(0, header_end));

    stream.ignore(256, ' ');
    stream >> status_code_;
    stream.ignore(256, '\n');

    while (stream) {
        std::string name, value;

        std::getline(stream, name, ':');
        stream.ignore(256, ' ');

        if (name == "Content-Length")
            stream >> content_length_;

        if (name == "X-LS")
            std::getline(stream, x_ls, '\r');

        if (name == "Connection") {
            std::string value;
            std::getline(stream, value, '\r');

            if (value == "Keep-Alive" || value == "Keep-alive" || value == "keep-alive")
                keep_alive = true;
        }

        stream.ignore(256, '\n');
    }

    response_str.erase(0, header_end + 4);
}
<|endoftext|>