<commit_before>//===------- X86InterleavedAccess.cpp --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the X86 implementation of the interleaved accesses
// optimization generating X86-specific instructions/intrinsics for interleaved
// access groups.
//
//===----------------------------------------------------------------------===//

#include "X86ISelLowering.h"
#include "X86TargetMachine.h"

using namespace llvm;

/// Returns true if the interleaved access group represented by the shuffles
/// is supported for the subtarget. Returns false otherwise.
static bool isSupported(const X86Subtarget &SubTarget,
                        const LoadInst *LI,
                        const ArrayRef<ShuffleVectorInst *> &Shuffles,
                        unsigned Factor) {

  const DataLayout &DL = Shuffles[0]->getModule()->getDataLayout();
  VectorType *ShuffleVecTy = Shuffles[0]->getType();
  unsigned ShuffleVecSize = DL.getTypeSizeInBits(ShuffleVecTy);
  Type *ShuffleEltTy = ShuffleVecTy->getVectorElementType();

  if (DL.getTypeSizeInBits(LI->getType()) < Factor * ShuffleVecSize)
    return false;

  // Currently, lowering is supported for 64 bits on AVX.
  if (!SubTarget.hasAVX() || ShuffleVecSize != 256 ||
      DL.getTypeSizeInBits(ShuffleEltTy) != 64 ||
      Factor != 4)
    return false;

  return true;
}

/// \brief Lower interleaved load(s) into target specific instructions/
/// intrinsics. Lowering sequence varies depending on the vector-types, factor,
/// number of shuffles and ISA.
/// Currently, lowering is supported for 4x64 bits with Factor = 4 on AVX.
bool X86TargetLowering::lowerInterleavedLoad(
    LoadInst *LI, ArrayRef<ShuffleVectorInst *> Shuffles,
    ArrayRef<unsigned> Indices, unsigned Factor) const {
  assert(Factor >= 2 && Factor <= getMaxSupportedInterleaveFactor() &&
         "Invalid interleave factor");
  assert(!Shuffles.empty() && "Empty shufflevector input");
  assert(Shuffles.size() == Indices.size() &&
         "Unmatched number of shufflevectors and indices");

  if (!isSupported(Subtarget, LI, Shuffles, Factor))
    return false;

  VectorType *ShuffleVecTy = Shuffles[0]->getType();

  Type *VecBasePtrTy = ShuffleVecTy->getPointerTo(LI->getPointerAddressSpace());

  IRBuilder<> Builder(LI);
  SmallVector<Instruction *, 4> NewLoads;
  SmallVector<Value *, 4> NewShuffles;
  NewShuffles.resize(Factor);

  Value *VecBasePtr =
      Builder.CreateBitCast(LI->getPointerOperand(), VecBasePtrTy);

  // Generate 4 loads of type v4xT64
  for (unsigned Part = 0; Part < Factor; Part++) {
    // TODO: Support inbounds GEP
    Value *NewBasePtr =
        Builder.CreateGEP(VecBasePtr, Builder.getInt32(Part));
    Instruction *NewLoad =
        Builder.CreateAlignedLoad(NewBasePtr, LI->getAlignment());
    NewLoads.push_back(NewLoad);
  }

  // dst = src1[0,1],src2[0,1]
  uint32_t IntMask1[] = {0, 1, 4, 5};
  ArrayRef<unsigned int> ShuffleMask = makeArrayRef(IntMask1, 4);
  Value *IntrVec1 =
      Builder.CreateShuffleVector(NewLoads[0], NewLoads[2], ShuffleMask);
  Value *IntrVec2 =
      Builder.CreateShuffleVector(NewLoads[1], NewLoads[3], ShuffleMask);

  // dst = src1[2,3],src2[2,3]
  uint32_t IntMask2[] = {2, 3, 6, 7};
  ShuffleMask = makeArrayRef(IntMask2, 4);
  Value *IntrVec3 =
      Builder.CreateShuffleVector(NewLoads[0], NewLoads[2], ShuffleMask);
  Value *IntrVec4 =
      Builder.CreateShuffleVector(NewLoads[1], NewLoads[3], ShuffleMask);

  // dst = src1[0],src2[0],src1[2],src2[2]
  uint32_t IntMask3[] = {0, 4, 2, 6};
  ShuffleMask = makeArrayRef(IntMask3, 4);
  NewShuffles[0] = Builder.CreateShuffleVector(IntrVec1, IntrVec2, ShuffleMask);
  NewShuffles[2] = Builder.CreateShuffleVector(IntrVec3, IntrVec4, ShuffleMask);

  // dst = src1[1],src2[1],src1[3],src2[3]
  uint32_t IntMask4[] = {1, 5, 3, 7};
  ShuffleMask = makeArrayRef(IntMask4, 4);
  NewShuffles[1] = Builder.CreateShuffleVector(IntrVec1, IntrVec2, ShuffleMask);
  NewShuffles[3] = Builder.CreateShuffleVector(IntrVec3, IntrVec4, ShuffleMask);

  for (unsigned i = 0; i < Shuffles.size(); i++) {
    unsigned Index = Indices[i];
    Shuffles[i]->replaceAllUsesWith(NewShuffles[Index]);
  }

  return true;
}
<commit_msg>Refactored X86InterleavedAccess into a class. NFCI.<commit_after>//===--------- X86InterleavedAccess.cpp ----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===--------------------------------------------------------------------===//
///
/// \file
/// This file contains the X86 implementation of the interleaved accesses
/// optimization generating X86-specific instructions/intrinsics for
/// interleaved access groups.
///
//===--------------------------------------------------------------------===//

#include "X86ISelLowering.h"
#include "X86TargetMachine.h"

using namespace llvm;

/// \brief This class holds necessary information to represent an interleaved
/// access group and supports utilities to lower the group into
/// X86-specific instructions/intrinsics.
///  E.g. A group of interleaving access loads (Factor = 2; accessing every
///       other element)
///        %wide.vec = load <8 x i32>, <8 x i32>* %ptr
///        %v0 = shuffle <8 x i32> %wide.vec, <8 x i32> undef, <0, 2, 4, 6>
///        %v1 = shuffle <8 x i32> %wide.vec, <8 x i32> undef, <1, 3, 5, 7>

class X86InterleavedAccessGroup {
  /// \brief Reference to the wide-load instruction of an interleaved access
  /// group.
  Instruction *const Inst;

  /// \brief Reference to the shuffle(s), consumer(s) of the (load) 'Inst'.
  ArrayRef<ShuffleVectorInst *> Shuffles;

  /// \brief Reference to the starting index of each user-shuffle.
  ArrayRef<unsigned> Indices;

  /// \brief Reference to the interleaving stride in terms of elements.
  const unsigned Factor;

  /// \brief Reference to the underlying target.
  const X86Subtarget &Subtarget;

  const DataLayout &DL;

  IRBuilder<> &Builder;

  /// \brief Breaks down a vector \p 'Inst' of N elements into \p NumSubVectors
  /// sub vectors of type \p T. Returns true and the sub-vectors in
  /// \p DecomposedVectors if it decomposes the Inst, returns false otherwise.
  bool decompose(Instruction *Inst, unsigned NumSubVectors, VectorType *T,
                 SmallVectorImpl<Instruction *> &DecomposedVectors);

  /// \brief Performs matrix transposition on a 4x4 matrix \p InputVectors and
  /// returns the transposed-vectors in \p TransposedVectors.
  /// E.g.
  /// InputVectors:
  ///   In-V0 = p1, p2, p3, p4
  ///   In-V1 = q1, q2, q3, q4
  ///   In-V2 = r1, r2, r3, r4
  ///   In-V3 = s1, s2, s3, s4
  /// OutputVectors:
  ///   Out-V0 = p1, q1, r1, s1
  ///   Out-V1 = p2, q2, r2, s2
  ///   Out-V2 = p3, q3, r3, s3
  ///   Out-V3 = P4, q4, r4, s4
  void transpose_4x4(ArrayRef<Instruction *> InputVectors,
                     SmallVectorImpl<Value *> &TrasposedVectors);

public:
  /// In order to form an interleaved access group X86InterleavedAccessGroup
  /// requires a wide-load instruction \p 'I', a group of interleaved-vectors
  /// \p Shuffs, reference to the first indices of each interleaved-vector
  /// \p 'Ind' and the interleaving stride factor \p F. In order to generate
  /// X86-specific instructions/intrinsics it also requires the underlying
  /// target information \p STarget.
  explicit X86InterleavedAccessGroup(Instruction *I,
                                     ArrayRef<ShuffleVectorInst *> Shuffs,
                                     ArrayRef<unsigned> Ind,
                                     const unsigned F,
                                     const X86Subtarget &STarget,
                                     IRBuilder<> &B)
      : Inst(I), Shuffles(Shuffs), Indices(Ind), Factor(F), Subtarget(STarget),
        DL(Inst->getModule()->getDataLayout()), Builder(B) {}

  /// \brief Returns true if this interleaved access group can be lowered into
  /// x86-specific instructions/intrinsics, false otherwise.
  bool isSupported() const;

  /// \brief Lowers this interleaved access group into X86-specific
  /// instructions/intrinsics.
  bool lowerIntoOptimizedSequence();
};

bool X86InterleavedAccessGroup::isSupported() const {
  VectorType *ShuffleVecTy = Shuffles[0]->getType();
  uint64_t ShuffleVecSize = DL.getTypeSizeInBits(ShuffleVecTy);
  Type *ShuffleEltTy = ShuffleVecTy->getVectorElementType();

  if (DL.getTypeSizeInBits(Inst->getType()) < Factor * ShuffleVecSize)
    return false;

  // Currently, lowering is supported for 64 bits on AVX.
  if (!Subtarget.hasAVX() || ShuffleVecSize != 256 ||
      DL.getTypeSizeInBits(ShuffleEltTy) != 64 || Factor != 4)
    return false;

  return true;
}

bool X86InterleavedAccessGroup::decompose(
    Instruction *VecInst, unsigned NumSubVectors, VectorType *SubVecTy,
    SmallVectorImpl<Instruction *> &DecomposedVectors) {
  Type *VecTy = VecInst->getType();

  assert(VecTy->isVectorTy() &&
         DL.getTypeSizeInBits(VecTy) >=
             DL.getTypeSizeInBits(SubVecTy) * NumSubVectors &&
         "Invalid Inst-size!!!");
  assert(VecTy->getVectorElementType() == SubVecTy->getVectorElementType() &&
         "Element type mismatched!!!");

  if (!isa<LoadInst>(VecInst))
    return false;

  LoadInst *LI = cast<LoadInst>(VecInst);
  Type *VecBasePtrTy = SubVecTy->getPointerTo(LI->getPointerAddressSpace());

  Value *VecBasePtr =
      Builder.CreateBitCast(LI->getPointerOperand(), VecBasePtrTy);

  // Generate N loads of T type
  for (unsigned i = 0; i < NumSubVectors; i++) {
    // TODO: Support inbounds GEP
    Value *NewBasePtr = Builder.CreateGEP(VecBasePtr, Builder.getInt32(i));
    Instruction *NewLoad =
        Builder.CreateAlignedLoad(NewBasePtr, LI->getAlignment());
    DecomposedVectors.push_back(NewLoad);
  }

  return true;
}

void X86InterleavedAccessGroup::transpose_4x4(
    ArrayRef<Instruction *> Matrix,
    SmallVectorImpl<Value *> &TransposedMatrix) {
  assert(Matrix.size() == 4 && "Invalid matrix size");
  TransposedMatrix.resize(4);

  // dst = src1[0,1],src2[0,1]
  uint32_t IntMask1[] = {0, 1, 4, 5};
  ArrayRef<uint32_t> Mask = makeArrayRef(IntMask1, 4);
  Value *IntrVec1 = Builder.CreateShuffleVector(Matrix[0], Matrix[2], Mask);
  Value *IntrVec2 = Builder.CreateShuffleVector(Matrix[1], Matrix[3], Mask);

  // dst = src1[2,3],src2[2,3]
  uint32_t IntMask2[] = {2, 3, 6, 7};
  Mask = makeArrayRef(IntMask2, 4);
  Value *IntrVec3 = Builder.CreateShuffleVector(Matrix[0], Matrix[2], Mask);
  Value *IntrVec4 = Builder.CreateShuffleVector(Matrix[1], Matrix[3], Mask);

  // dst = src1[0],src2[0],src1[2],src2[2]
  uint32_t IntMask3[] = {0, 4, 2, 6};
  Mask = makeArrayRef(IntMask3, 4);
  TransposedMatrix[0] = Builder.CreateShuffleVector(IntrVec1, IntrVec2, Mask);
  TransposedMatrix[2] = Builder.CreateShuffleVector(IntrVec3, IntrVec4, Mask);

  // dst = src1[1],src2[1],src1[3],src2[3]
  uint32_t IntMask4[] = {1, 5, 3, 7};
  Mask = makeArrayRef(IntMask4, 4);
  TransposedMatrix[1] = Builder.CreateShuffleVector(IntrVec1, IntrVec2, Mask);
  TransposedMatrix[3] = Builder.CreateShuffleVector(IntrVec3, IntrVec4, Mask);
}

// Lowers this interleaved access group into X86-specific
// instructions/intrinsics.
bool X86InterleavedAccessGroup::lowerIntoOptimizedSequence() {
  SmallVector<Instruction *, 4> DecomposedVectors;
  VectorType *VecTy = Shuffles[0]->getType();
  // Try to generate target-sized register(/instruction).
  if (!decompose(Inst, Factor, VecTy, DecomposedVectors))
    return false;

  SmallVector<Value *, 4> TransposedVectors;
  // Perform matrix-transposition in order to compute interleaved
  // results by generating some sort of (optimized) target-specific
  // instructions.
  transpose_4x4(DecomposedVectors, TransposedVectors);

  // Now replace the unoptimized-interleaved-vectors with the
  // transposed-interleaved vectors.
  for (unsigned i = 0; i < Shuffles.size(); i++)
    Shuffles[i]->replaceAllUsesWith(TransposedVectors[Indices[i]]);

  return true;
}

// Lower interleaved load(s) into target specific instructions/
// intrinsics. Lowering sequence varies depending on the vector-types, factor,
// number of shuffles and ISA.
// Currently, lowering is supported for 4x64 bits with Factor = 4 on AVX.
bool X86TargetLowering::lowerInterleavedLoad(
    LoadInst *LI, ArrayRef<ShuffleVectorInst *> Shuffles,
    ArrayRef<unsigned> Indices, unsigned Factor) const {
  assert(Factor >= 2 && Factor <= getMaxSupportedInterleaveFactor() &&
         "Invalid interleave factor");
  assert(!Shuffles.empty() && "Empty shufflevector input");
  assert(Shuffles.size() == Indices.size() &&
         "Unmatched number of shufflevectors and indices");

  // Create an interleaved access group.
  IRBuilder<> Builder(LI);
  X86InterleavedAccessGroup Grp(LI, Shuffles, Indices, Factor, Subtarget,
                                Builder);

  return Grp.isSupported() && Grp.lowerIntoOptimizedSequence();
}
<|endoftext|>


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

 medInria

 Copyright (c) INRIA 2013. All rights reserved.
 See LICENSE.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

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

#include "medDatabaseNavigatorItem.h"
#include <medDatabaseNavigatorItemOverlay.h>
#include "medImageFileLoader.h"

#include <medCore/medAbstractDbController.h>
#include <medCore/medDataManager.h>
#include <medCore/medMetaDataKeys.h>

#include <QtCore>
#include <QtGui>

// /////////////////////////////////////////////////////////////////
// medDatabaseNavigatorItem
// /////////////////////////////////////////////////////////////////

// -- TODO
//
// Passing database indexes as arguments to the constructor is more than
// sufficient.
//
// Attributes such as path to thumbnail, count and text should be retrieved
// from the database.

class medDatabaseNavigatorItemPrivate
{
public:
    medDataIndex index;
    bool persistent;
    QString text;

    medDatabaseNavigatorItemOverlay *itemSaver;
    medDatabaseNavigatorItemOverlay *itemExporter;
    medDatabaseNavigatorItemOverlay *itemTrasher;

    QPropertyAnimation *itemSaverFadingAnimation;
    QPropertyAnimation *itemExporterFadingAnimation;
    QPropertyAnimation *itemTrasherFadingAnimation;

    QParallelAnimationGroup *fadingAnimation;
};

medDatabaseNavigatorItem::medDatabaseNavigatorItem(const medDataIndex & index,  QGraphicsItem *parent) : QObject(), QGraphicsPixmapItem(QPixmap(":/pixmap/thumbnail_default.tiff"), parent), d(new medDatabaseNavigatorItemPrivate)
{
    d->index = index;

    medAbstractDbController * dbc = medDataManager::instance()->controllerForDataSource(index.dataSourceId());
    QString thumbpath = dbc->metaData(index,medMetaDataKeys::ThumbnailPath);

    d->persistent = dbc->isPersistent();
    d->text = dbc->metaData(index,medMetaDataKeys::SeriesDescription);

    bool shouldSkipLoading = false;
    if ( thumbpath.isEmpty() ) {
        // first try to get it from controller
        QImage thumbImage = dbc->thumbnail(index);
        if (!thumbImage.isNull())
        {
            this->setImage( thumbImage );
            shouldSkipLoading = true;
        }
    }

    if (!shouldSkipLoading) {
        medImageFileLoader *loader = new medImageFileLoader(thumbpath);
        connect(loader, SIGNAL(completed(const QImage&)), this, SLOT(setImage(const QImage&)));
        QThreadPool::globalInstance()->start(loader);
    }

    this->setAcceptHoverEvents(true);

    d->itemExporter = new medDatabaseNavigatorItemOverlay(this);
    d->itemExporter->setToolTip("Export data to disk");
    QPixmap pixmap(":/icons/export.png");
    d->itemExporter->setPixmap(pixmap);
    d->itemExporter->setPos(10, 45);
    d->itemExporter->setOpacity(0.0);

    connect(d->itemExporter, SIGNAL(clicked()), this, SLOT(exportData()));

    // Setup animation
    d->itemExporterFadingAnimation = new QPropertyAnimation(d->itemExporter, "opacity", this);
    d->itemExporterFadingAnimation->setDuration(150);

    d->fadingAnimation = new QParallelAnimationGroup(this);
    d->fadingAnimation->addAnimation(d->itemExporterFadingAnimation);

    if (!d->persistent)
    {
        d->itemSaver = new medDatabaseNavigatorItemOverlay(this);
        QPixmap pixmapSave(":/icons/import.png");
        d->itemSaver->setToolTip("Save data to database");
        d->itemSaver->setPixmap(pixmapSave);
        d->itemSaver->setPos(10, 65);
        d->itemSaver->setOpacity(0.0);

        connect(d->itemSaver, SIGNAL(clicked()), this, SLOT(saveData()));

        // Setup animation
        d->itemSaverFadingAnimation = new QPropertyAnimation(d->itemSaver, "opacity", this);
        d->itemSaverFadingAnimation->setDuration(150);

        d->fadingAnimation->addAnimation(d->itemSaverFadingAnimation);
    }
    else
    {
        d->itemSaver = NULL;
        d->itemSaverFadingAnimation = NULL;
    }

    d->itemTrasher = new medDatabaseNavigatorItemOverlay(this);
    d->itemTrasher->setToolTip("Remove data");
    QPixmap pixmapDelete(":/icons/cross.svg");
    d->itemTrasher->setPixmap(pixmapDelete.scaledToWidth(16));
    d->itemTrasher->setPos(10, 25);
    d->itemTrasher->setOpacity(0.0);

    connect(d->itemTrasher, SIGNAL(clicked()), this, SLOT(deleteData()));

    // Setup animation
    d->itemTrasherFadingAnimation = new QPropertyAnimation(d->itemTrasher, "opacity", this);
    d->itemTrasherFadingAnimation->setDuration(150);

    d->fadingAnimation->addAnimation(d->itemTrasherFadingAnimation);

    connect(this, SIGNAL(itemDoubleClicked(const medDataIndex&)), medDataManager::instance(), SIGNAL(openRequested(const medDataIndex&)));
}

medDatabaseNavigatorItem::~medDatabaseNavigatorItem(void)
{
    delete d;

    d = NULL;
}

medDatabaseNavigatorItem *medDatabaseNavigatorItem::clone(void)
{
    return new medDatabaseNavigatorItem(d->index, 0);
}

void medDatabaseNavigatorItem::setup(void)
{
    // Retrieve attributes from the database
}

medDataIndex medDatabaseNavigatorItem::dataIndex(void) const
{
    return d->index;
}

QString medDatabaseNavigatorItem::text(void) const
{
    return d->text;
}

void medDatabaseNavigatorItem::deleteData()
{
    int reply = QMessageBox::question(NULL, tr("Remove item"),
                                      tr("Are you sure you want to continue removing this data?\n""This cannot be undone."),
                                      QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton);

    if( reply == QMessageBox::Yes )
        medDataManager::instance()->removeData(d->index);
}

void medDatabaseNavigatorItem::saveData()
{
    medDataManager::instance()->storeNonPersistentSingleDataToDatabase(d->index);
}

void medDatabaseNavigatorItem::exportData()
{
    QString fileName = QFileDialog::getSaveFileName(NULL, tr("Save as"), "", "*.*");

    if (fileName.isEmpty())
        return;

    dtkSmartPointer<dtkAbstractData> data = medDataManager::instance()->data(d->index);

    if (!data)
        return;

    //Check extension:
    QFileInfo fileInfo(fileName);
    if(fileInfo.suffix().isEmpty())
    {
        qDebug() << "determining suffix for type" << data->identifier();
        if (data->identifier().contains("vtk") ||
            data->identifier().contains("v3d"))
            fileName.append(".vtk");
        else
            fileName.append(".nii.gz");
        qDebug() << "filename:" << fileName;
        //There may be other cases, but this will get us through most
    }

    medDataManager::instance()->exportDataToFile(data, fileName);
}

void medDatabaseNavigatorItem::setImage(const QImage& image)
{
    this->setPixmap(QPixmap::fromImage(image));
}

void medDatabaseNavigatorItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

void medDatabaseNavigatorItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
{
    emit itemDoubleClicked(d->index);
}

void medDatabaseNavigatorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    QMimeData *data = d->index.createMimeData();
    data->setImageData(this->pixmap());

	QDrag *drag = new QDrag(this->scene()->views().first());
    drag->setMimeData(data);
#if WIN32
	drag->setPixmap(this->pixmap().scaled(64,64));
#else
    drag->setPixmap(this->pixmap());
#endif
    drag->setHotSpot(QPoint(drag->pixmap().width()/2, drag->pixmap().height()/2));
    drag->start();
}

void medDatabaseNavigatorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    if(d->persistent)
        painter->setBrush(Qt::darkGray);
    else
        painter->setBrush(QColor(129, 143, 164));
    painter->setPen(Qt::NoPen);
    painter->drawRoundedRect(option->rect.adjusted(-8,-8, 8, 8),5,5);

    QGraphicsPixmapItem::paint (painter, option, widget);

    painter->setPen(Qt::white);
    painter->drawText(option->rect.adjusted(5, 5, -5, option->rect.height()-5), Qt::AlignRight | Qt::TextSingleLine, d->text);
}

void medDatabaseNavigatorItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
    if (d->itemSaverFadingAnimation)
    {
        d->itemSaverFadingAnimation->setStartValue(0.0);
        d->itemSaverFadingAnimation->setEndValue(1.0);
    }

    d->itemExporterFadingAnimation->setStartValue(0.0);
    d->itemExporterFadingAnimation->setEndValue(1.0);

    d->itemTrasherFadingAnimation->setStartValue(0.0);
    d->itemTrasherFadingAnimation->setEndValue(1.0);

    d->fadingAnimation->start();
}

void medDatabaseNavigatorItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    if (d->itemSaverFadingAnimation)
    {
        d->itemSaverFadingAnimation->setStartValue(1.0);
        d->itemSaverFadingAnimation->setEndValue(0.0);
    }

    d->itemExporterFadingAnimation->setStartValue(1.0);
    d->itemExporterFadingAnimation->setEndValue(0.0);

    d->itemTrasherFadingAnimation->setStartValue(1.0);
    d->itemTrasherFadingAnimation->setEndValue(0.0);

    d->fadingAnimation->start();
}
<commit_msg>fix #1742, adds tooltips for each of the navigator items<commit_after>/*=========================================================================

 medInria

 Copyright (c) INRIA 2013. All rights reserved.
 See LICENSE.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

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

#include "medDatabaseNavigatorItem.h"
#include <medDatabaseNavigatorItemOverlay.h>
#include "medImageFileLoader.h"

#include <medCore/medAbstractDbController.h>
#include <medCore/medDataManager.h>
#include <medCore/medMetaDataKeys.h>

#include <QtCore>
#include <QtGui>

// /////////////////////////////////////////////////////////////////
// medDatabaseNavigatorItem
// /////////////////////////////////////////////////////////////////

// -- TODO
//
// Passing database indexes as arguments to the constructor is more than
// sufficient.
//
// Attributes such as path to thumbnail, count and text should be retrieved
// from the database.

class medDatabaseNavigatorItemPrivate
{
public:
    medDataIndex index;
    bool persistent;
    QString text;

    medDatabaseNavigatorItemOverlay *itemSaver;
    medDatabaseNavigatorItemOverlay *itemExporter;
    medDatabaseNavigatorItemOverlay *itemTrasher;

    QPropertyAnimation *itemSaverFadingAnimation;
    QPropertyAnimation *itemExporterFadingAnimation;
    QPropertyAnimation *itemTrasherFadingAnimation;

    QParallelAnimationGroup *fadingAnimation;
};

medDatabaseNavigatorItem::medDatabaseNavigatorItem(const medDataIndex & index,  QGraphicsItem *parent) : QObject(), QGraphicsPixmapItem(QPixmap(":/pixmap/thumbnail_default.tiff"), parent), d(new medDatabaseNavigatorItemPrivate)
{
    d->index = index;

    medAbstractDbController * dbc = medDataManager::instance()->controllerForDataSource(index.dataSourceId());
    QString thumbpath = dbc->metaData(index,medMetaDataKeys::ThumbnailPath);

    d->persistent = dbc->isPersistent();
    d->text = dbc->metaData(index,medMetaDataKeys::SeriesDescription);
    this->setToolTip("" + d->text + "");

    bool shouldSkipLoading = false;
    if ( thumbpath.isEmpty() ) {
        // first try to get it from controller
        QImage thumbImage = dbc->thumbnail(index);
        if (!thumbImage.isNull())
        {
            this->setImage( thumbImage );
            shouldSkipLoading = true;
        }
    }

    if (!shouldSkipLoading) {
        medImageFileLoader *loader = new medImageFileLoader(thumbpath);
        connect(loader, SIGNAL(completed(const QImage&)), this, SLOT(setImage(const QImage&)));
        QThreadPool::globalInstance()->start(loader);
    }

    this->setAcceptHoverEvents(true);

    d->itemExporter = new medDatabaseNavigatorItemOverlay(this);
    d->itemExporter->setToolTip("Export data to disk");
    QPixmap pixmap(":/icons/export.png");
    d->itemExporter->setPixmap(pixmap);
    d->itemExporter->setPos(10, 45);
    d->itemExporter->setOpacity(0.0);

    connect(d->itemExporter, SIGNAL(clicked()), this, SLOT(exportData()));

    // Setup animation
    d->itemExporterFadingAnimation = new QPropertyAnimation(d->itemExporter, "opacity", this);
    d->itemExporterFadingAnimation->setDuration(150);

    d->fadingAnimation = new QParallelAnimationGroup(this);
    d->fadingAnimation->addAnimation(d->itemExporterFadingAnimation);

    if (!d->persistent)
    {
        d->itemSaver = new medDatabaseNavigatorItemOverlay(this);
        QPixmap pixmapSave(":/icons/import.png");
        d->itemSaver->setToolTip("Save data to database");
        d->itemSaver->setPixmap(pixmapSave);
        d->itemSaver->setPos(10, 65);
        d->itemSaver->setOpacity(0.0);

        connect(d->itemSaver, SIGNAL(clicked()), this, SLOT(saveData()));

        // Setup animation
        d->itemSaverFadingAnimation = new QPropertyAnimation(d->itemSaver, "opacity", this);
        d->itemSaverFadingAnimation->setDuration(150);

        d->fadingAnimation->addAnimation(d->itemSaverFadingAnimation);
    }
    else
    {
        d->itemSaver = NULL;
        d->itemSaverFadingAnimation = NULL;
    }

    d->itemTrasher = new medDatabaseNavigatorItemOverlay(this);
    d->itemTrasher->setToolTip("Remove data");
    QPixmap pixmapDelete(":/icons/cross.svg");
    d->itemTrasher->setPixmap(pixmapDelete.scaledToWidth(16));
    d->itemTrasher->setPos(10, 25);
    d->itemTrasher->setOpacity(0.0);

    connect(d->itemTrasher, SIGNAL(clicked()), this, SLOT(deleteData()));

    // Setup animation
    d->itemTrasherFadingAnimation = new QPropertyAnimation(d->itemTrasher, "opacity", this);
    d->itemTrasherFadingAnimation->setDuration(150);

    d->fadingAnimation->addAnimation(d->itemTrasherFadingAnimation);

    connect(this, SIGNAL(itemDoubleClicked(const medDataIndex&)), medDataManager::instance(), SIGNAL(openRequested(const medDataIndex&)));
}

medDatabaseNavigatorItem::~medDatabaseNavigatorItem(void)
{
    delete d;

    d = NULL;
}

medDatabaseNavigatorItem *medDatabaseNavigatorItem::clone(void)
{
    return new medDatabaseNavigatorItem(d->index, 0);
}

void medDatabaseNavigatorItem::setup(void)
{
    // Retrieve attributes from the database
}

medDataIndex medDatabaseNavigatorItem::dataIndex(void) const
{
    return d->index;
}

QString medDatabaseNavigatorItem::text(void) const
{
    return d->text;
}

void medDatabaseNavigatorItem::deleteData()
{
    int reply = QMessageBox::question(NULL, tr("Remove item"),
                                      tr("Are you sure you want to continue removing this data?\n""This cannot be undone."),
                                      QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton);

    if( reply == QMessageBox::Yes )
        medDataManager::instance()->removeData(d->index);
}

void medDatabaseNavigatorItem::saveData()
{
    medDataManager::instance()->storeNonPersistentSingleDataToDatabase(d->index);
}

void medDatabaseNavigatorItem::exportData()
{
    QString fileName = QFileDialog::getSaveFileName(NULL, tr("Save as"), "", "*.*");

    if (fileName.isEmpty())
        return;

    dtkSmartPointer<dtkAbstractData> data = medDataManager::instance()->data(d->index);

    if (!data)
        return;

    //Check extension:
    QFileInfo fileInfo(fileName);
    if(fileInfo.suffix().isEmpty())
    {
        qDebug() << "determining suffix for type" << data->identifier();
        if (data->identifier().contains("vtk") ||
            data->identifier().contains("v3d"))
            fileName.append(".vtk");
        else
            fileName.append(".nii.gz");
        qDebug() << "filename:" << fileName;
        //There may be other cases, but this will get us through most
    }

    medDataManager::instance()->exportDataToFile(data, fileName);
}

void medDatabaseNavigatorItem::setImage(const QImage& image)
{
    this->setPixmap(QPixmap::fromImage(image));
}

void medDatabaseNavigatorItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

void medDatabaseNavigatorItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
{
    emit itemDoubleClicked(d->index);
}

void medDatabaseNavigatorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    QMimeData *data = d->index.createMimeData();
    data->setImageData(this->pixmap());

	QDrag *drag = new QDrag(this->scene()->views().first());
    drag->setMimeData(data);
#if WIN32
	drag->setPixmap(this->pixmap().scaled(64,64));
#else
    drag->setPixmap(this->pixmap());
#endif
    drag->setHotSpot(QPoint(drag->pixmap().width()/2, drag->pixmap().height()/2));
    drag->start();
}

void medDatabaseNavigatorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    if(d->persistent)
        painter->setBrush(Qt::darkGray);
    else
        painter->setBrush(QColor(129, 143, 164));
    painter->setPen(Qt::NoPen);
    painter->drawRoundedRect(option->rect.adjusted(-8,-8, 8, 8),5,5);

    QGraphicsPixmapItem::paint (painter, option, widget);

    painter->setPen(Qt::white);
    painter->drawText(option->rect.adjusted(5, 5, -5, option->rect.height()-5), Qt::AlignRight | Qt::TextSingleLine, d->text);
}

void medDatabaseNavigatorItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
    if (d->itemSaverFadingAnimation)
    {
        d->itemSaverFadingAnimation->setStartValue(0.0);
        d->itemSaverFadingAnimation->setEndValue(1.0);
    }

    d->itemExporterFadingAnimation->setStartValue(0.0);
    d->itemExporterFadingAnimation->setEndValue(1.0);

    d->itemTrasherFadingAnimation->setStartValue(0.0);
    d->itemTrasherFadingAnimation->setEndValue(1.0);

    d->fadingAnimation->start();
}

void medDatabaseNavigatorItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    if (d->itemSaverFadingAnimation)
    {
        d->itemSaverFadingAnimation->setStartValue(1.0);
        d->itemSaverFadingAnimation->setEndValue(0.0);
    }

    d->itemExporterFadingAnimation->setStartValue(1.0);
    d->itemExporterFadingAnimation->setEndValue(0.0);

    d->itemTrasherFadingAnimation->setStartValue(1.0);
    d->itemTrasherFadingAnimation->setEndValue(0.0);

    d->fadingAnimation->start();
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright 2016 IBM Corp.
 *
 * 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.
 *******************************************************************************/

#if defined(_ZOS)
#define _UNIX03_SOURCE
#endif

#include "ibmras/common/util/LibraryUtils.h"

#if defined(WINDOWS)
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
const char PATHSEPARATOR = '\\';
#else
#include <dlfcn.h>
#include <errno.h>
const char PATHSEPARATOR = '/';
#endif

namespace ibmras {
namespace common {
namespace util {

void* LibraryUtils::getSymbol(Handle libHandle, const std::string& symbolName) {

	void *symbol = NULL;

#if defined(WINDOWS)
	symbol = (void*) GetProcAddress(libHandle.handle, symbolName.c_str());
#else
	/* Unix platforms */
	symbol = dlsym(libHandle.handle, symbolName.c_str());
#endif

	return symbol;

}

ibmras::common::util::LibraryUtils::Handle LibraryUtils::openLibrary(const std::string& lib) {

	Handle handle;
#if defined(WINDOWS)
	handle.handle = LoadLibrary(lib.c_str());
#else
        handle.handle = dlopen(lib.c_str(), RTLD_LAZY | RTLD_NOLOAD)
        if (handle.handle == null) {
	   handle.handle = dlopen(lib.c_str(), RTLD_LAZY);
        }
#endif
	return handle;
}

void LibraryUtils::closeLibrary(Handle libHandle) {

#if defined(WINDOWS)
	FreeLibrary(libHandle.handle);
#else
	dlclose(libHandle.handle);
#endif
	libHandle.handle = NULL;
}

std::string LibraryUtils::getLibraryLocation(const void* func) {
	std::string path;

#if defined (WINDOWS)
#elif defined(AIX)
#elif defined(_ZOS)
#else
	Dl_info dlInfo;
	int rc = dladdr(func, &dlInfo);
	if (rc != 0) {
		path = dlInfo.dli_fname;
	}

#endif
	return path;
}

std::string LibraryUtils::getLibraryDir(const std::string &library, const void* func) {
	std::string path;
#if defined (WINDOWS)
	path = getLibraryLocation(library);
#else
	path = getLibraryLocation(func);
#endif
	size_t pos = path.find_last_of(PATHSEPARATOR);
	if (pos != std::string::npos) {
		path = path.substr(0, pos);
	}
	return path;
}

std::string LibraryUtils::getLibraryLocation(const std::string &library) {
	std::string path;

#if defined (WINDOWS)
	HMODULE hModule = GetModuleHandle(library.c_str());
	TCHAR dllPath[_MAX_PATH];
	GetModuleFileName(hModule, dllPath, _MAX_PATH);
	path = dllPath;
#else
#endif
	return path;
}

}
}
}
<commit_msg>C requires semi-colons as statement terminators<commit_after>/*******************************************************************************
 * Copyright 2016 IBM Corp.
 *
 * 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.
 *******************************************************************************/

#if defined(_ZOS)
#define _UNIX03_SOURCE
#endif

#include "ibmras/common/util/LibraryUtils.h"

#if defined(WINDOWS)
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
const char PATHSEPARATOR = '\\';
#else
#include <dlfcn.h>
#include <errno.h>
const char PATHSEPARATOR = '/';
#endif

namespace ibmras {
namespace common {
namespace util {

void* LibraryUtils::getSymbol(Handle libHandle, const std::string& symbolName) {

	void *symbol = NULL;

#if defined(WINDOWS)
	symbol = (void*) GetProcAddress(libHandle.handle, symbolName.c_str());
#else
	/* Unix platforms */
	symbol = dlsym(libHandle.handle, symbolName.c_str());
#endif

	return symbol;

}

ibmras::common::util::LibraryUtils::Handle LibraryUtils::openLibrary(const std::string& lib) {

	Handle handle;
#if defined(WINDOWS)
	handle.handle = LoadLibrary(lib.c_str());
#else
        handle.handle = dlopen(lib.c_str(), RTLD_LAZY | RTLD_NOLOAD);
        if (handle.handle == null) {
	   handle.handle = dlopen(lib.c_str(), RTLD_LAZY);
        }
#endif
	return handle;
}

void LibraryUtils::closeLibrary(Handle libHandle) {

#if defined(WINDOWS)
	FreeLibrary(libHandle.handle);
#else
	dlclose(libHandle.handle);
#endif
	libHandle.handle = NULL;
}

std::string LibraryUtils::getLibraryLocation(const void* func) {
	std::string path;

#if defined (WINDOWS)
#elif defined(AIX)
#elif defined(_ZOS)
#else
	Dl_info dlInfo;
	int rc = dladdr(func, &dlInfo);
	if (rc != 0) {
		path = dlInfo.dli_fname;
	}

#endif
	return path;
}

std::string LibraryUtils::getLibraryDir(const std::string &library, const void* func) {
	std::string path;
#if defined (WINDOWS)
	path = getLibraryLocation(library);
#else
	path = getLibraryLocation(func);
#endif
	size_t pos = path.find_last_of(PATHSEPARATOR);
	if (pos != std::string::npos) {
		path = path.substr(0, pos);
	}
	return path;
}

std::string LibraryUtils::getLibraryLocation(const std::string &library) {
	std::string path;

#if defined (WINDOWS)
	HMODULE hModule = GetModuleHandle(library.c_str());
	TCHAR dllPath[_MAX_PATH];
	GetModuleFileName(hModule, dllPath, _MAX_PATH);
	path = dllPath;
#else
#endif
	return path;
}

}
}
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015-2019 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#ifndef HAVE_LIBVLC
# error This file requires libvlc
#endif

#include "VLCMetadataService.h"
#include "utils/VLCInstance.h"
#include "metadata_services/vlc/Common.hpp"
#include "utils/Filename.h"
#include "logging/Logger.h"
#include "utils/Url.h"
#include "utils/Md5.h"
#include "utils/Defer.h"

#ifndef USE_EMBEDDED_THUMBNAIL_API
# include "utils/File.h"
#endif

namespace medialibrary
{
namespace parser
{

bool VLCMetadataService::initialize( IMediaLibrary* )
{
    return true;
}

#if defined(FORCE_ATTACHMENTS_API)

void VLCMetadataService::onAttachedThumbnailsFound( const libvlc_event_t* e, void* data )
{
    assert( e->type == libvlc_MediaAttachedThumbnailsFound );
    auto item = reinterpret_cast<IItem*>( data );
    auto pictureList = e->u.media_attached_thumbnails_found.thumbnails;
    if ( libvlc_picture_list_count( pictureList ) == 0 )
        return;
    item->addEmbeddedThumbnail( std::make_shared<VLCEmbeddedThumbnailForced>(
                                    libvlc_picture_list_at( pictureList, 0 ) ) );
}

#endif

Status VLCMetadataService::run( IItem& item )
{
    auto mrl = item.mrl();

    // Having a valid media means we're re-executing this parser after the thumbnailer,
    // which isn't expected, as we always mark this task as completed.
    VLC::Media vlcMedia{ VLCInstance::get(), mrl, VLC::Media::FromType::FromLocation };

    VLC::Media::ParsedStatus status;
    bool done = false;

    {
        /*
         * Store a copy of the event manager. When the instance falls out of
         * scope, all events registered through it will be unregistered
         * automatically
         */
        auto em = vlcMedia.eventManager();
        em.onParsedChanged( [this, &status, &done](VLC::Media::ParsedStatus s ) {
            std::lock_guard<compat::Mutex> lock( m_mutex );
            status = s;
            done = true;
            m_cond.notify_all();
        });
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)
        em.onAttachedThumbnailsFound( [&item]( const std::vector<VLC::Picture>& pics ) {
            if ( pics.empty() == false )
            {
                item.addEmbeddedThumbnail(
                            std::make_shared<VLCEmbeddedThumbnail4_0>( pics[0] ) );
            }
        });
#elif defined(FORCE_ATTACHMENTS_API)
        /*
         * We can force the use of the 4.0 attachment API if the patches have
         * been backported to 3.0, however libvlcpp doesn't expose it so we have
         * to fallback to the C API
         */
        if ( libvlc_event_attach( em, libvlc_MediaAttachedThumbnailsFound,
                             &onAttachedThumbnailsFound, &item ) != 0 )
        {
            LOG_ERROR( "Failed to attach to thumbnail found event" );
            return Status::Fatal;
        }
        auto unregister = utils::make_defer([&em, &item]() {
            libvlc_event_detach( em, libvlc_MediaAttachedThumbnailsFound,
                                 &onAttachedThumbnailsFound, &item );
        });
#endif

        {
            // We need m_currentMedia to be updated from a locked context
            // but we also need parseWithOption to be called with the lock
            // unlocked, to avoid a potential lock inversion with VLC's internal
            // mutexes.
            std::unique_lock<compat::Mutex> lock( m_mutex );
            m_currentMedia = vlcMedia;
        }

        if ( vlcMedia.parseWithOptions( VLC::Media::ParseFlags::Local |
                                        VLC::Media::ParseFlags::Network, 5000 ) == false )
        {
            std::unique_lock<compat::Mutex> lock( m_mutex );
            m_currentMedia = VLC::Media{};
            return Status::Fatal;
        }
        std::unique_lock<compat::Mutex> lock( m_mutex );
        m_cond.wait( lock, [&done]() {
            return done == true;
        });
        m_currentMedia = VLC::Media{};
    }
    if ( status == VLC::Media::ParsedStatus::Failed || status == VLC::Media::ParsedStatus::Timeout )
        return Status::Fatal;
    if ( item.fileType() == IFile::Type::Playlist &&
         vlcMedia.subitems()->count() == 0 )
    {
        LOG_DEBUG( "Discarding playlist file with no subitem: ", mrl );
        return Status::Fatal;
    }
#if LIBVLC_VERSION_INT < LIBVLC_VERSION(4, 0, 0, 0) && !defined(FORCE_ATTACHMENTS_API)
    auto artworkMrl = vlcMedia.meta( libvlc_meta_ArtworkURL );
    if ( artworkMrl.empty() == false )
    {
        if ( utils::url::schemeIs( "attachment://", artworkMrl ) == true )
        {
            LOG_WARN( "Artwork for ", mrl, " is an attachment. Falling back to playback" );
            VLC::MediaPlayer mp( vlcMedia );
            auto res = MetadataCommon::startPlayback( vlcMedia, mp, m_mutex, m_cond );
            if ( res == false )
                return Status::Fatal;
        }
        item.addEmbeddedThumbnail( std::make_shared<VLCEmbeddedThumbnail3_0>(
            utils::url::toLocalPath( vlcMedia.meta( libvlc_meta_ArtworkURL ) ) ) );
    }
#endif
    mediaToItem( vlcMedia, item );
    return Status::Success;
}

const char* VLCMetadataService::name() const
{
    return "VLC";
}

void VLCMetadataService::onFlushing()
{
}

void VLCMetadataService::onRestarted()
{
}

Step VLCMetadataService::targetedStep() const
{
    return Step::MetadataExtraction;
}

void VLCMetadataService::stop()
{
    std::lock_guard<compat::Mutex> lock{ m_mutex };
    if ( m_currentMedia.isValid() )
        m_currentMedia.parseStop();
}

void VLCMetadataService::mediaToItem( VLC::Media& media, IItem& item )
{
    item.setMeta( IItem::Metadata::Title,
                  media.meta( libvlc_meta_Title ) );
    item.setMeta( IItem::Metadata::ArtworkUrl,
                  media.meta( libvlc_meta_ArtworkURL ) );
    item.setMeta( IItem::Metadata::ShowName,
                  media.meta( libvlc_meta_ShowName ) );
    item.setMeta( IItem::Metadata::Episode,
                  media.meta( libvlc_meta_Episode ) );
    item.setMeta( IItem::Metadata::Album,
                  media.meta( libvlc_meta_Album ) );
    item.setMeta( IItem::Metadata::Genre,
                  media.meta( libvlc_meta_Genre ) );
    item.setMeta( IItem::Metadata::Date,
                  media.meta( libvlc_meta_Date ) );
    item.setMeta( IItem::Metadata::AlbumArtist,
                  media.meta( libvlc_meta_AlbumArtist ) );
    item.setMeta( IItem::Metadata::Artist,
                  media.meta( libvlc_meta_Artist ) );
    item.setMeta( IItem::Metadata::TrackNumber,
                  media.meta( libvlc_meta_TrackNumber ) );
    item.setMeta( IItem::Metadata::DiscNumber,
                  media.meta( libvlc_meta_DiscNumber ) );
    item.setMeta( IItem::Metadata::DiscTotal,
                  media.meta( libvlc_meta_DiscTotal ) );
    item.setDuration( media.duration() );

#if LIBVLC_VERSION_INT < LIBVLC_VERSION(4, 0, 0, 0)
    auto tracks = media.tracks();
#else
    std::vector<VLC::MediaTrack> tracks;
    auto trackList = media.tracks( VLC::MediaTrack::Type::Audio );
    std::move( begin( trackList ), end( trackList ), std::back_inserter( tracks ) );
    trackList = media.tracks( VLC::MediaTrack::Type::Video );
    std::move( begin( trackList ), end( trackList ), std::back_inserter( tracks ) );
    trackList = media.tracks( VLC::MediaTrack::Type::Subtitle );
    std::move( begin( trackList ), end( trackList ), std::back_inserter( tracks ) );
#endif
    for ( const auto& track : tracks )
    {
        IItem::Track t;

        if ( track.type() == VLC::MediaTrack::Type::Audio )
        {
            t.type = IItem::Track::Type::Audio;
            t.a.nbChannels = track.channels();
            t.a.rate = track.rate();
        }
        else if ( track.type() == VLC::MediaTrack::Type::Video )
        {
            t.type = IItem::Track::Type::Video;
            t.v.fpsNum = track.fpsNum();
            t.v.fpsDen = track.fpsDen();
            t.v.width = track.width();
            t.v.height = track.height();
            t.v.sarNum = track.sarNum();
            t.v.sarDen = track.sarDen();
        }
        else if ( track.type() == VLC::MediaTrack::Type::Subtitle )
        {
            t.type = IItem::Track::Type::Subtitle;
            t.language = track.language();
            t.description = track.description();
            const auto& enc = track.encoding();
            strncpy( t.s.encoding, enc.c_str(), sizeof(t.s.encoding) - 1 );
        }
        else
            continue;
        auto codec = track.codec();
        std::string fcc( reinterpret_cast<const char*>( &codec ), 4 );
        t.codec = std::move( fcc );

        t.bitrate = track.bitrate();
        t.language = track.language();
        t.description = track.description();

        item.addTrack( std::move( t ) );
    }

    auto subItems = media.subitems();
    if ( subItems != nullptr )
    {
        for ( auto i = 0; i < subItems->count(); ++i )
        {
            auto vlcMedia = subItems->itemAtIndex( i );
            assert( vlcMedia != nullptr );
            auto mrl = vlcMedia->mrl();
            mrl = utils::url::encode( utils::url::decode( mrl ) );
            IItem& subItem = item.createLinkedItem( mrl,
                                                    IFile::Type::Main, i );
            mediaToItem( *vlcMedia, subItem );
        }
    }
}

#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)

VLCEmbeddedThumbnail4_0::VLCEmbeddedThumbnail4_0( VLC::Picture pic )
    : m_pic( std::move( pic ) )
{
}

bool VLCEmbeddedThumbnail4_0::save( const std::string& path )
{
    return m_pic.save( path );
}

size_t VLCEmbeddedThumbnail4_0::size() const
{
    size_t size;
    m_pic.buffer( &size );
    return size;
}

std::string VLCEmbeddedThumbnail4_0::hash() const
{
    size_t size;
    auto buff = m_pic.buffer( &size );
    return utils::Md5Hasher::fromBuff( buff, size );
}

std::string VLCEmbeddedThumbnail4_0::extension() const
{
    switch ( m_pic.type() )
    {
    case VLC::Picture::Type::Argb:
        return "bmp";
    case VLC::Picture::Type::Jpg:
        return "jpg";
    case VLC::Picture::Type::Png:
        return "png";
    }
    assert( !"Invalid thumbnail type" );
    return {};
}

#elif defined(FORCE_ATTACHMENTS_API)

VLCEmbeddedThumbnailForced::VLCEmbeddedThumbnailForced( libvlc_picture_t *pic )
    : m_pic( pic )
{
    libvlc_picture_retain( m_pic );
}

VLCEmbeddedThumbnailForced::~VLCEmbeddedThumbnailForced()
{
    libvlc_picture_release( m_pic );
}

bool VLCEmbeddedThumbnailForced::save( const std::string& path )
{
    return libvlc_picture_save( m_pic, path.c_str() ) == 0;
}

size_t VLCEmbeddedThumbnailForced::size() const
{
    size_t size;
    libvlc_picture_get_buffer( m_pic, &size );
    return size;
}

std::string VLCEmbeddedThumbnailForced::hash() const
{
    size_t size;
    auto buff = libvlc_picture_get_buffer( m_pic, &size );
    return utils::Md5Hasher::fromBuff( buff, size );
}

std::string VLCEmbeddedThumbnailForced::extension() const
{
    switch ( libvlc_picture_type( m_pic ) )
    {
    case libvlc_picture_Argb:
        return "bmp";
    case libvlc_picture_Jpg:
        return "jpg";
    case libvlc_picture_Png:
        return "png";
    }
    assert( !"Invalid thumbnail type" );
    return nullptr;
}

#else

VLCEmbeddedThumbnail3_0::VLCEmbeddedThumbnail3_0( std::string path )
    : m_thumbnailPath( std::move( path ) )
{
}

bool VLCEmbeddedThumbnail3_0::save( const std::string& path )
{
    return utils::fs::copy( m_thumbnailPath, path );
}

size_t VLCEmbeddedThumbnail3_0::size() const
{
    return utils::fs::fileSize( m_thumbnailPath );
}

std::string VLCEmbeddedThumbnail3_0::hash() const
{
    return utils::Md5Hasher::fromFile( m_thumbnailPath );
}

std::string VLCEmbeddedThumbnail3_0::extension() const
{
    return utils::file::extension( m_thumbnailPath );
}

#endif

}
}
<commit_msg>VLCMetadataService: Use XXhash instead of md5<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015-2019 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#ifndef HAVE_LIBVLC
# error This file requires libvlc
#endif

#include "VLCMetadataService.h"
#include "utils/VLCInstance.h"
#include "metadata_services/vlc/Common.hpp"
#include "utils/Filename.h"
#include "logging/Logger.h"
#include "utils/Url.h"
#include "utils/Md5.h"
#include "utils/XxHasher.h"
#include "utils/Defer.h"

#ifndef USE_EMBEDDED_THUMBNAIL_API
# include "utils/File.h"
#endif

namespace medialibrary
{
namespace parser
{

bool VLCMetadataService::initialize( IMediaLibrary* )
{
    return true;
}

#if defined(FORCE_ATTACHMENTS_API)

void VLCMetadataService::onAttachedThumbnailsFound( const libvlc_event_t* e, void* data )
{
    assert( e->type == libvlc_MediaAttachedThumbnailsFound );
    auto item = reinterpret_cast<IItem*>( data );
    auto pictureList = e->u.media_attached_thumbnails_found.thumbnails;
    if ( libvlc_picture_list_count( pictureList ) == 0 )
        return;
    item->addEmbeddedThumbnail( std::make_shared<VLCEmbeddedThumbnailForced>(
                                    libvlc_picture_list_at( pictureList, 0 ) ) );
}

#endif

Status VLCMetadataService::run( IItem& item )
{
    auto mrl = item.mrl();

    // Having a valid media means we're re-executing this parser after the thumbnailer,
    // which isn't expected, as we always mark this task as completed.
    VLC::Media vlcMedia{ VLCInstance::get(), mrl, VLC::Media::FromType::FromLocation };

    VLC::Media::ParsedStatus status;
    bool done = false;

    {
        /*
         * Store a copy of the event manager. When the instance falls out of
         * scope, all events registered through it will be unregistered
         * automatically
         */
        auto em = vlcMedia.eventManager();
        em.onParsedChanged( [this, &status, &done](VLC::Media::ParsedStatus s ) {
            std::lock_guard<compat::Mutex> lock( m_mutex );
            status = s;
            done = true;
            m_cond.notify_all();
        });
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)
        em.onAttachedThumbnailsFound( [&item]( const std::vector<VLC::Picture>& pics ) {
            if ( pics.empty() == false )
            {
                item.addEmbeddedThumbnail(
                            std::make_shared<VLCEmbeddedThumbnail4_0>( pics[0] ) );
            }
        });
#elif defined(FORCE_ATTACHMENTS_API)
        /*
         * We can force the use of the 4.0 attachment API if the patches have
         * been backported to 3.0, however libvlcpp doesn't expose it so we have
         * to fallback to the C API
         */
        if ( libvlc_event_attach( em, libvlc_MediaAttachedThumbnailsFound,
                             &onAttachedThumbnailsFound, &item ) != 0 )
        {
            LOG_ERROR( "Failed to attach to thumbnail found event" );
            return Status::Fatal;
        }
        auto unregister = utils::make_defer([&em, &item]() {
            libvlc_event_detach( em, libvlc_MediaAttachedThumbnailsFound,
                                 &onAttachedThumbnailsFound, &item );
        });
#endif

        {
            // We need m_currentMedia to be updated from a locked context
            // but we also need parseWithOption to be called with the lock
            // unlocked, to avoid a potential lock inversion with VLC's internal
            // mutexes.
            std::unique_lock<compat::Mutex> lock( m_mutex );
            m_currentMedia = vlcMedia;
        }

        if ( vlcMedia.parseWithOptions( VLC::Media::ParseFlags::Local |
                                        VLC::Media::ParseFlags::Network, 5000 ) == false )
        {
            std::unique_lock<compat::Mutex> lock( m_mutex );
            m_currentMedia = VLC::Media{};
            return Status::Fatal;
        }
        std::unique_lock<compat::Mutex> lock( m_mutex );
        m_cond.wait( lock, [&done]() {
            return done == true;
        });
        m_currentMedia = VLC::Media{};
    }
    if ( status == VLC::Media::ParsedStatus::Failed || status == VLC::Media::ParsedStatus::Timeout )
        return Status::Fatal;
    if ( item.fileType() == IFile::Type::Playlist &&
         vlcMedia.subitems()->count() == 0 )
    {
        LOG_DEBUG( "Discarding playlist file with no subitem: ", mrl );
        return Status::Fatal;
    }
#if LIBVLC_VERSION_INT < LIBVLC_VERSION(4, 0, 0, 0) && !defined(FORCE_ATTACHMENTS_API)
    auto artworkMrl = vlcMedia.meta( libvlc_meta_ArtworkURL );
    if ( artworkMrl.empty() == false )
    {
        if ( utils::url::schemeIs( "attachment://", artworkMrl ) == true )
        {
            LOG_WARN( "Artwork for ", mrl, " is an attachment. Falling back to playback" );
            VLC::MediaPlayer mp( vlcMedia );
            auto res = MetadataCommon::startPlayback( vlcMedia, mp, m_mutex, m_cond );
            if ( res == false )
                return Status::Fatal;
        }
        item.addEmbeddedThumbnail( std::make_shared<VLCEmbeddedThumbnail3_0>(
            utils::url::toLocalPath( vlcMedia.meta( libvlc_meta_ArtworkURL ) ) ) );
    }
#endif
    mediaToItem( vlcMedia, item );
    return Status::Success;
}

const char* VLCMetadataService::name() const
{
    return "VLC";
}

void VLCMetadataService::onFlushing()
{
}

void VLCMetadataService::onRestarted()
{
}

Step VLCMetadataService::targetedStep() const
{
    return Step::MetadataExtraction;
}

void VLCMetadataService::stop()
{
    std::lock_guard<compat::Mutex> lock{ m_mutex };
    if ( m_currentMedia.isValid() )
        m_currentMedia.parseStop();
}

void VLCMetadataService::mediaToItem( VLC::Media& media, IItem& item )
{
    item.setMeta( IItem::Metadata::Title,
                  media.meta( libvlc_meta_Title ) );
    item.setMeta( IItem::Metadata::ArtworkUrl,
                  media.meta( libvlc_meta_ArtworkURL ) );
    item.setMeta( IItem::Metadata::ShowName,
                  media.meta( libvlc_meta_ShowName ) );
    item.setMeta( IItem::Metadata::Episode,
                  media.meta( libvlc_meta_Episode ) );
    item.setMeta( IItem::Metadata::Album,
                  media.meta( libvlc_meta_Album ) );
    item.setMeta( IItem::Metadata::Genre,
                  media.meta( libvlc_meta_Genre ) );
    item.setMeta( IItem::Metadata::Date,
                  media.meta( libvlc_meta_Date ) );
    item.setMeta( IItem::Metadata::AlbumArtist,
                  media.meta( libvlc_meta_AlbumArtist ) );
    item.setMeta( IItem::Metadata::Artist,
                  media.meta( libvlc_meta_Artist ) );
    item.setMeta( IItem::Metadata::TrackNumber,
                  media.meta( libvlc_meta_TrackNumber ) );
    item.setMeta( IItem::Metadata::DiscNumber,
                  media.meta( libvlc_meta_DiscNumber ) );
    item.setMeta( IItem::Metadata::DiscTotal,
                  media.meta( libvlc_meta_DiscTotal ) );
    item.setDuration( media.duration() );

#if LIBVLC_VERSION_INT < LIBVLC_VERSION(4, 0, 0, 0)
    auto tracks = media.tracks();
#else
    std::vector<VLC::MediaTrack> tracks;
    auto trackList = media.tracks( VLC::MediaTrack::Type::Audio );
    std::move( begin( trackList ), end( trackList ), std::back_inserter( tracks ) );
    trackList = media.tracks( VLC::MediaTrack::Type::Video );
    std::move( begin( trackList ), end( trackList ), std::back_inserter( tracks ) );
    trackList = media.tracks( VLC::MediaTrack::Type::Subtitle );
    std::move( begin( trackList ), end( trackList ), std::back_inserter( tracks ) );
#endif
    for ( const auto& track : tracks )
    {
        IItem::Track t;

        if ( track.type() == VLC::MediaTrack::Type::Audio )
        {
            t.type = IItem::Track::Type::Audio;
            t.a.nbChannels = track.channels();
            t.a.rate = track.rate();
        }
        else if ( track.type() == VLC::MediaTrack::Type::Video )
        {
            t.type = IItem::Track::Type::Video;
            t.v.fpsNum = track.fpsNum();
            t.v.fpsDen = track.fpsDen();
            t.v.width = track.width();
            t.v.height = track.height();
            t.v.sarNum = track.sarNum();
            t.v.sarDen = track.sarDen();
        }
        else if ( track.type() == VLC::MediaTrack::Type::Subtitle )
        {
            t.type = IItem::Track::Type::Subtitle;
            t.language = track.language();
            t.description = track.description();
            const auto& enc = track.encoding();
            strncpy( t.s.encoding, enc.c_str(), sizeof(t.s.encoding) - 1 );
        }
        else
            continue;
        auto codec = track.codec();
        std::string fcc( reinterpret_cast<const char*>( &codec ), 4 );
        t.codec = std::move( fcc );

        t.bitrate = track.bitrate();
        t.language = track.language();
        t.description = track.description();

        item.addTrack( std::move( t ) );
    }

    auto subItems = media.subitems();
    if ( subItems != nullptr )
    {
        for ( auto i = 0; i < subItems->count(); ++i )
        {
            auto vlcMedia = subItems->itemAtIndex( i );
            assert( vlcMedia != nullptr );
            auto mrl = vlcMedia->mrl();
            mrl = utils::url::encode( utils::url::decode( mrl ) );
            IItem& subItem = item.createLinkedItem( mrl,
                                                    IFile::Type::Main, i );
            mediaToItem( *vlcMedia, subItem );
        }
    }
}

#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)

VLCEmbeddedThumbnail4_0::VLCEmbeddedThumbnail4_0( VLC::Picture pic )
    : m_pic( std::move( pic ) )
{
}

bool VLCEmbeddedThumbnail4_0::save( const std::string& path )
{
    return m_pic.save( path );
}

size_t VLCEmbeddedThumbnail4_0::size() const
{
    size_t size;
    m_pic.buffer( &size );
    return size;
}

std::string VLCEmbeddedThumbnail4_0::hash() const
{
    size_t size;
    auto buff = m_pic.buffer( &size );
    return utils::hash::toString( utils::hash::xxFromBuff( buff, size ) );
}

std::string VLCEmbeddedThumbnail4_0::extension() const
{
    switch ( m_pic.type() )
    {
    case VLC::Picture::Type::Argb:
        return "bmp";
    case VLC::Picture::Type::Jpg:
        return "jpg";
    case VLC::Picture::Type::Png:
        return "png";
    }
    assert( !"Invalid thumbnail type" );
    return {};
}

#elif defined(FORCE_ATTACHMENTS_API)

VLCEmbeddedThumbnailForced::VLCEmbeddedThumbnailForced( libvlc_picture_t *pic )
    : m_pic( pic )
{
    libvlc_picture_retain( m_pic );
}

VLCEmbeddedThumbnailForced::~VLCEmbeddedThumbnailForced()
{
    libvlc_picture_release( m_pic );
}

bool VLCEmbeddedThumbnailForced::save( const std::string& path )
{
    return libvlc_picture_save( m_pic, path.c_str() ) == 0;
}

size_t VLCEmbeddedThumbnailForced::size() const
{
    size_t size;
    libvlc_picture_get_buffer( m_pic, &size );
    return size;
}

std::string VLCEmbeddedThumbnailForced::hash() const
{
    size_t size;
    auto buff = libvlc_picture_get_buffer( m_pic, &size );
    return utils::hash::toString( utils::hash::xxFromBuff( buff, size ) );
}

std::string VLCEmbeddedThumbnailForced::extension() const
{
    switch ( libvlc_picture_type( m_pic ) )
    {
    case libvlc_picture_Argb:
        return "bmp";
    case libvlc_picture_Jpg:
        return "jpg";
    case libvlc_picture_Png:
        return "png";
    }
    assert( !"Invalid thumbnail type" );
    return nullptr;
}

#else

VLCEmbeddedThumbnail3_0::VLCEmbeddedThumbnail3_0( std::string path )
    : m_thumbnailPath( std::move( path ) )
{
}

bool VLCEmbeddedThumbnail3_0::save( const std::string& path )
{
    return utils::fs::copy( m_thumbnailPath, path );
}

size_t VLCEmbeddedThumbnail3_0::size() const
{
    return utils::fs::fileSize( m_thumbnailPath );
}

std::string VLCEmbeddedThumbnail3_0::hash() const
{
    return utils::hash::toString( utils::hash::xxFromFile( m_thumbnailPath ) );
}

std::string VLCEmbeddedThumbnail3_0::extension() const
{
    return utils::file::extension( m_thumbnailPath );
}

#endif

}
}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2014, 2015 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file mavlink_orb_subscription.cpp
 * uORB subscription implementation.
 *
 * @author Anton Babushkin <anton.babushkin@me.com>
 * @author Lorenz Meier <lorenz@px4.io>
 */

#include "mavlink_orb_subscription.h"

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <px4_defines.h>
#include <uORB/uORB.h>

MavlinkOrbSubscription::MavlinkOrbSubscription(const orb_id_t topic, int instance) :
	_topic(topic),
	_instance(instance)
{
}

MavlinkOrbSubscription::~MavlinkOrbSubscription()
{
	if (_fd >= 0) {
		orb_unsubscribe(_fd);
	}
}

orb_id_t
MavlinkOrbSubscription::get_topic() const
{
	return _topic;
}

int
MavlinkOrbSubscription::get_instance() const
{
	return _instance;
}

bool
MavlinkOrbSubscription::update(uint64_t *time, void *data)
{
	// TODO this is NOT atomic operation, we can get data newer than time
	// if topic was published between orb_stat and orb_copy calls.

	if (!is_published()) {
		return false;
	}

	uint64_t time_topic;

	if (orb_stat(_fd, &time_topic)) {
		/* error getting last topic publication time */
		time_topic = 0;
	}

	if (time_topic == 0 || (time_topic != *time)) {
		if (orb_copy(_topic, _fd, data) == PX4_OK) {
			/* data copied successfully */
			*time = time_topic;
			return true;
		}
	}

	return false;
}

bool
MavlinkOrbSubscription::update(void *data)
{
	if (!is_published()) {
		return false;
	}

	if (orb_copy(_topic, _fd, data) != PX4_OK) {
		return false;
	}

	return true;
}

bool
MavlinkOrbSubscription::update_if_changed(void *data)
{
	bool prevpub = _published;

	if (!is_published()) {
		return false;
	}

	bool updated;

	if (orb_check(_fd, &updated)) {
		return false;
	}

	// If we didn't update and this topic did not change
	// its publication status then nothing really changed
	if (!updated && prevpub == _published) {
		return false;
	}

	return update(data);
}

bool
MavlinkOrbSubscription::is_published()
{
	// If we marked it as published no need to check again
	if (_published) {
		return true;
	}

	hrt_abstime now = hrt_absolute_time();

	if (now - _last_pub_check < 300000) {
		return false;
	}

	// We are checking now
	_last_pub_check = now;

	// We don't want to subscribe to anything that does not exist
	// in order to save memory and file descriptors.
	// However, for some topics like vehicle_command_ack, we want to subscribe
	// from the beginning in order not to miss the first publish respective advertise.
	if (!_subscribe_from_beginning && orb_exists(_topic, _instance)) {
		return false;
	}

	if (_fd < 0) {
		_fd = orb_subscribe_multi(_topic, _instance);
	}

	bool updated;
	orb_check(_fd, &updated);

	if (updated) {
		_published = true;
	}

	// topic may have been last published before we subscribed
	uint64_t time_topic = 0;

	if (!_published && orb_stat(_fd, &time_topic) == PX4_OK) {
		if (time_topic != 0) {
			_published = true;
		}
	}

	return _published;
}

void
MavlinkOrbSubscription::subscribe_from_beginning(bool from_beginning)
{
	_subscribe_from_beginning = from_beginning;
}
<commit_msg>mavlink_orb_subscription: remove unneeded checks<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2014, 2015 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file mavlink_orb_subscription.cpp
 * uORB subscription implementation.
 *
 * @author Anton Babushkin <anton.babushkin@me.com>
 * @author Lorenz Meier <lorenz@px4.io>
 */

#include "mavlink_orb_subscription.h"

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <px4_defines.h>
#include <uORB/uORB.h>

MavlinkOrbSubscription::MavlinkOrbSubscription(const orb_id_t topic, int instance) :
	_topic(topic),
	_instance(instance)
{
}

MavlinkOrbSubscription::~MavlinkOrbSubscription()
{
	if (_fd >= 0) {
		orb_unsubscribe(_fd);
	}
}

orb_id_t
MavlinkOrbSubscription::get_topic() const
{
	return _topic;
}

int
MavlinkOrbSubscription::get_instance() const
{
	return _instance;
}

bool
MavlinkOrbSubscription::update(uint64_t *time, void *data)
{
	// TODO this is NOT atomic operation, we can get data newer than time
	// if topic was published between orb_stat and orb_copy calls.

	if (!is_published()) {
		return false;
	}

	uint64_t time_topic;

	if (orb_stat(_fd, &time_topic)) {
		/* error getting last topic publication time */
		time_topic = 0;
	}

	if (time_topic == 0 || (time_topic != *time)) {
		if (orb_copy(_topic, _fd, data) == PX4_OK) {
			/* data copied successfully */
			*time = time_topic;
			return true;
		}
	}

	return false;
}

bool
MavlinkOrbSubscription::update(void *data)
{
	if (!is_published()) {
		return false;
	}

	if (orb_copy(_topic, _fd, data) != PX4_OK) {
		return false;
	}

	return true;
}

bool
MavlinkOrbSubscription::update_if_changed(void *data)
{
	if (!is_published()) {
		return false;
	}

	bool updated;

	if (orb_check(_fd, &updated) || !updated) {
		return false;
	}

	return update(data);
}

bool
MavlinkOrbSubscription::is_published()
{
	// If we marked it as published no need to check again
	if (_published) {
		return true;
	}

	hrt_abstime now = hrt_absolute_time();

	if (now - _last_pub_check < 300000) {
		return false;
	}

	// We are checking now
	_last_pub_check = now;

	// We don't want to subscribe to anything that does not exist
	// in order to save memory and file descriptors.
	// However, for some topics like vehicle_command_ack, we want to subscribe
	// from the beginning in order not to miss or delay the first publish respective advertise.
	if (!_subscribe_from_beginning && orb_exists(_topic, _instance)) {
		return false;
	}

	if (_fd < 0) {
		_fd = orb_subscribe_multi(_topic, _instance);
	}

	bool updated;
	orb_check(_fd, &updated);

	if (updated) {
		_published = true;
	}

	return _published;
}

void
MavlinkOrbSubscription::subscribe_from_beginning(bool from_beginning)
{
	_subscribe_from_beginning = from_beginning;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * MediaDiscoverer.hpp: MediaDiscoverer API
 *****************************************************************************
 * Copyright © 2015 libvlcpp authors & VideoLAN
 *
 * Authors: Alexey Sokolov <alexey@alexeysokolov.co.cc>
 *          Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifndef LIBVLC_CXX_MEDIADISCOVERER_H
#define LIBVLC_CXX_MEDIADISCOVERER_H

#include "common.hpp"

#include <string>

namespace VLC
{

class MediaDiscovererEventManager;
class Instance;

class MediaDiscoverer : public Internal<libvlc_media_discoverer_t>
{
public:
    // libvlc_media_discoverer_new_from_name
    /**
     * Discover media service by name.
     *
     * \param p_inst  libvlc instance
     *
     * \param psz_name  service name
     * \warning This is returned as a pointer, as this is not refcounter by VLC, and is
     *          fairly expensive to instantiate.
     */
    MediaDiscoverer(Instance& inst, const std::string& name)
        : Internal{ libvlc_media_discoverer_new_from_name(getInternalPtr<libvlc_instance_t>( inst ), name.c_str()),
                    libvlc_media_discoverer_release }
    {
    }

    /**
     * Get media service discover object its localized name.
     *
     * \return localized name
     */
    std::string localizedName()
    {
        auto str = wrapCStr( libvlc_media_discoverer_localized_name(*this) );
        if ( str == nullptr )
            return {};
        return str.get();
    }

    /**
     * Get event manager from media service discover object.
     *
     * \return event manager object.
     */
    MediaDiscovererEventManager& eventManager()
    {
        if ( m_eventManager )
        {
            libvlc_event_manager_t* obj = libvlc_media_discoverer_event_manager( *this );
            m_eventManager = std::make_shared<MediaDiscovererEventManager>( obj );
        }
        return *m_eventManager;
    }

    /**
     * Query if media service discover object is running.
     *
     * \return true if running, false if not
     */
    bool isRunning()
    {
        return libvlc_media_discoverer_is_running(*this) != 0;
    }

private:
    std::shared_ptr<MediaDiscovererEventManager> m_eventManager;
};

} // namespace VLC

#endif

<commit_msg>MediaDiscoverer: Add binding for 3.0 functions<commit_after>/*****************************************************************************
 * MediaDiscoverer.hpp: MediaDiscoverer API
 *****************************************************************************
 * Copyright © 2015 libvlcpp authors & VideoLAN
 *
 * Authors: Alexey Sokolov <alexey@alexeysokolov.co.cc>
 *          Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifndef LIBVLC_CXX_MEDIADISCOVERER_H
#define LIBVLC_CXX_MEDIADISCOVERER_H

#include "common.hpp"

#include <string>
#include <vlc/libvlc_version.h>

namespace VLC
{

class MediaDiscovererEventManager;
class Instance;

class MediaDiscoverer : public Internal<libvlc_media_discoverer_t>
{
public:
    /**
     * Discover media service by name.
     *
     * \param p_inst  libvlc instance
     *
     * \param psz_name  service name
     * \warning This is returned as a pointer, as this is not refcounter by VLC, and is
     *          fairly expensive to instantiate.
     */
    MediaDiscoverer(Instance& inst, const std::string& name)
#if LIBVLC_VERSION(3, 0, 0, 0) >= LIBVLC_VERSION_INT
        : Internal{ libvlc_media_discoverer_new(getInternalPtr<libvlc_instance_t>( inst ), name.c_str()),
#else
        : Internal{ libvlc_media_discoverer_new_from_name(getInternalPtr<libvlc_instance_t>( inst ), name.c_str()),
#endif
                    libvlc_media_discoverer_release }
    {
    }

#if LIBVLC_VERSION(3, 0, 0, 0) >= LIBVLC_VERSION_INT
    /**
     * Start media discovery.
     *
     * To stop it, call MediaDiscover::stop() or
     * destroy the object directly.
     *
     * \see MediaDiscover::stop
     *
     * \return false in case of error, true otherwise
     */
    bool start()
    {
        return libvlc_media_discoverer_start( *this ) == 0;
    }

    /**
     * Stop media discovery.
     *
     * \see MediaDiscoverer::start()
     */
    void stop()
    {
        libvlc_media_discoverer_stop( *this );
    }
#endif

    /**
     * Get media service discover object its localized name.
     *
     * \return localized name
     */
    std::string localizedName()
    {
        auto str = wrapCStr( libvlc_media_discoverer_localized_name(*this) );
        if ( str == nullptr )
            return {};
        return str.get();
    }

    /**
     * Get event manager from media service discover object.
     *
     * \return event manager object.
     */
    MediaDiscovererEventManager& eventManager()
    {
        if ( m_eventManager )
        {
            libvlc_event_manager_t* obj = libvlc_media_discoverer_event_manager( *this );
            m_eventManager = std::make_shared<MediaDiscovererEventManager>( obj );
        }
        return *m_eventManager;
    }

    /**
     * Query if media service discover object is running.
     *
     * \return true if running, false if not
     */
    bool isRunning()
    {
        return libvlc_media_discoverer_is_running(*this) != 0;
    }

private:
    std::shared_ptr<MediaDiscovererEventManager> m_eventManager;
};

} // namespace VLC

#endif

<|endoftext|>


<commit_before>// http://bit.ly/1Je539P

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sndfile.h>

using namespace std;

int main(int argc, char **argv)
{
    if (argc != 3) {
        cout << "usage: " << argv[0] << " file.wav file.dat" << endl;
        exit(-1);
    }
    SNDFILE *sf;
    SF_INFO info;
    int num_channels;
    int num, num_items;
    int *buf;
    int f,sr,c;
    int i,j;
    FILE *out;

    /* Open the WAV file. */
    info.format = 0;
    sf = sf_open(argv[1], SFM_READ, &info);
    if (sf == NULL)
    {
        printf("Failed to open the file.\n");
        exit(-1);
    }
    /* Print some of the info, and figure out how much data to read. */
    f = info.frames;
    sr = info.samplerate;
    c = 1/*info.channels*/;
    printf("frames=%d\n",f);
    printf("samplerate=%d\n",sr);
    printf("channels=%d\n",c);
    num_items = f*c;
    printf("num_items=%d\n",num_items);
    /* Allocate space for the data to be read, then read it. */
    buf = (int *) malloc(num_items*sizeof(int));
    num = sf_read_int(sf,buf,num_items);
    sf_close(sf);
    printf("Read %d items\n",num);
    /* Write the data to filedata.out. */
    out = fopen(argv[2], "w");
    for (i = 0; i < num; i += c)
    {
        for (j = 0; j < c; ++j)
        {
            fprintf(out, "%f", (float) buf[i+j] / 4294967296.0f);
            if (j + 1 < c)
                fprintf(out, ",");
        }
        fprintf(out,",");
    }
    fclose(out);
    return 0;
}<commit_msg>wav_decode: no trainling comma at the end<commit_after>// http://bit.ly/1Je539P

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sndfile.h>

using namespace std;

int main(int argc, char **argv)
{
    if (argc != 3) {
        cout << "usage: " << argv[0] << " file.wav file.dat" << endl;
        exit(-1);
    }
    SNDFILE *sf;
    SF_INFO info;
    int num_channels;
    int num, num_items;
    int *buf;
    int f,sr,c;
    int i,j;
    FILE *out;

    /* Open the WAV file. */
    info.format = 0;
    sf = sf_open(argv[1], SFM_READ, &info);
    if (sf == NULL)
    {
        printf("Failed to open the file.\n");
        exit(-1);
    }
    /* Print some of the info, and figure out how much data to read. */
    f = info.frames;
    sr = info.samplerate;
    c = 1/*info.channels*/;
    printf("frames=%d\n",f);
    printf("samplerate=%d\n",sr);
    printf("channels=%d\n",c);
    num_items = f*c;
    printf("num_items=%d\n",num_items);
    /* Allocate space for the data to be read, then read it. */
    buf = (int *) malloc(num_items*sizeof(int));
    num = sf_read_int(sf,buf,num_items);
    sf_close(sf);
    printf("Read %d items\n",num);
    /* Write the data to filedata.out. */
    out = fopen(argv[2], "w");
    for (i = 0; i < num; i += c)
    {
        for (j = 0; j < c; ++j)
        {
            fprintf(out, "%f", (float) buf[i+j] / 4294967296.0f);
            if (j + 1 < c)
                fprintf(out, ",");
        }
        if (i + 1 < num)
            fprintf(out,",");
    }
    fclose(out);
    return 0;
}<|endoftext|>


<commit_before><commit_msg>lucy_bloom: improve blur quality by not skipping texels<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/app/atom_content_client.h"

#include <string>
#include <vector>

#include "atom/common/atom_version.h"
#include "atom/common/options_switches.h"
#include "atom/common/pepper_flash_util.h"
#include "base/command_line.h"
#include "base/debug/crash_logging.h"
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/chrome_version.h"
#include "chrome/common/crash_keys.h"
#include "chrome/common/extensions/extension_process_policy.h"
#include "chrome/common/secure_origin_whitelist.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/pepper_plugin_info.h"
#include "content/public/common/user_agent.h"
#include "extensions/features/features.h"
#include "gpu/config/gpu_info.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "url/url_constants.h"
#include "widevine_cdm_version.h"  // NOLINT

#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "content/public/common/url_constants.h"
#include "extensions/common/constants.h"
#include "extensions/common/features/feature_util.h"
#endif

namespace atom {

namespace {
void ConvertStringWithSeparatorToVector(std::vector<std::string>* vec,
                                        const char* separator,
                                        const char* cmd_switch) {
  auto command_line = base::CommandLine::ForCurrentProcess();
  auto string_with_separator = command_line->GetSwitchValueASCII(cmd_switch);
  if (!string_with_separator.empty())
    *vec = base::SplitString(string_with_separator, separator,
                             base::TRIM_WHITESPACE,
                             base::SPLIT_WANT_NONEMPTY);
}

}  // namespace

AtomContentClient::AtomContentClient() {
}

AtomContentClient::~AtomContentClient() {
}

void AtomContentClient::SetGpuInfo(const gpu::GPUInfo& gpu_info) {
  base::debug::SetCrashKeyValue(crash_keys::kGPUVendorID,
      base::StringPrintf("0x%04x", gpu_info.gpu.vendor_id));
  base::debug::SetCrashKeyValue(crash_keys::kGPUDeviceID,
      base::StringPrintf("0x%04x", gpu_info.gpu.device_id));
  base::debug::SetCrashKeyValue(crash_keys::kGPUDriverVersion,
      gpu_info.driver_version);
  base::debug::SetCrashKeyValue(crash_keys::kGPUPixelShaderVersion,
      gpu_info.pixel_shader_version);
  base::debug::SetCrashKeyValue(crash_keys::kGPUVertexShaderVersion,
      gpu_info.vertex_shader_version);
#if defined(OS_MACOSX)
  base::debug::SetCrashKeyValue(crash_keys::kGPUGLVersion, gpu_info.gl_version);
#elif defined(OS_POSIX)
  base::debug::SetCrashKeyValue(crash_keys::kGPUVendor, gpu_info.gl_vendor);
  base::debug::SetCrashKeyValue(crash_keys::kGPURenderer, gpu_info.gl_renderer);
#endif
}

std::string AtomContentClient::GetProduct() const {
  return "Chrome/" CHROME_VERSION_STRING;
}

std::string AtomContentClient::GetUserAgent() const {
  return content::BuildUserAgentFromProduct(
      "Chrome/" CHROME_VERSION_STRING);
}

bool AtomContentClient::IsSupplementarySiteIsolationModeEnabled() {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  return extensions::IsIsolateExtensionsEnabled();
#else
  return false;
#endif
}

void AtomContentClient::AddAdditionalSchemes(Schemes* schemes) {
  schemes->standard_schemes.push_back(extensions::kExtensionScheme);
  schemes->savable_schemes.push_back(extensions::kExtensionScheme);
  schemes->secure_schemes.push_back(extensions::kExtensionScheme);
  schemes->secure_origins = GetSecureOriginWhitelist();

#if BUILDFLAG(ENABLE_EXTENSIONS)
  if (extensions::feature_util::ExtensionServiceWorkersEnabled())
    schemes->service_worker_schemes.push_back(extensions::kExtensionScheme);

  // As far as Blink is concerned, they should be allowed to receive CORS
  // requests. At the Extensions layer, requests will actually be blocked unless
  // overridden by the web_accessible_resources manifest key.
  // TODO(kalman): See what happens with a service worker.
  schemes->cors_enabled_schemes.push_back(extensions::kExtensionScheme);
#endif
}

bool AtomContentClient::AllowScriptExtensionForServiceWorker(
    const GURL& script_url) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  return script_url.SchemeIs(extensions::kExtensionScheme);
#else
  return false;
#endif
}

content::OriginTrialPolicy* AtomContentClient::GetOriginTrialPolicy() {
  if (!origin_trial_policy_) {
    origin_trial_policy_ = base::WrapUnique(new ChromeOriginTrialPolicy());
  }
  return origin_trial_policy_.get();
}

void AtomContentClient::AddPepperPlugins(
    std::vector<content::PepperPluginInfo>* plugins) {
  AddPepperFlashFromCommandLine(plugins);
}

}  // namespace atom
<commit_msg>crash_keys -> gpu::crash_keys<commit_after>// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/app/atom_content_client.h"

#include <string>
#include <vector>

#include "atom/common/atom_version.h"
#include "atom/common/options_switches.h"
#include "atom/common/pepper_flash_util.h"
#include "base/command_line.h"
#include "base/debug/crash_logging.h"
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/chrome_version.h"
#include "chrome/common/crash_keys.h"
#include "chrome/common/extensions/extension_process_policy.h"
#include "chrome/common/secure_origin_whitelist.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/pepper_plugin_info.h"
#include "content/public/common/user_agent.h"
#include "extensions/features/features.h"
#include "gpu/config/gpu_crash_keys.h"
#include "gpu/config/gpu_info.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "url/url_constants.h"
#include "widevine_cdm_version.h"  // NOLINT

#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "content/public/common/url_constants.h"
#include "extensions/common/constants.h"
#include "extensions/common/features/feature_util.h"
#endif

namespace atom {

namespace {
void ConvertStringWithSeparatorToVector(std::vector<std::string>* vec,
                                        const char* separator,
                                        const char* cmd_switch) {
  auto command_line = base::CommandLine::ForCurrentProcess();
  auto string_with_separator = command_line->GetSwitchValueASCII(cmd_switch);
  if (!string_with_separator.empty())
    *vec = base::SplitString(string_with_separator, separator,
                             base::TRIM_WHITESPACE,
                             base::SPLIT_WANT_NONEMPTY);
}

}  // namespace

AtomContentClient::AtomContentClient() {
}

AtomContentClient::~AtomContentClient() {
}

void AtomContentClient::SetGpuInfo(const gpu::GPUInfo& gpu_info) {
  base::debug::SetCrashKeyValue(gpu::crash_keys::kGPUVendorID,
      base::StringPrintf("0x%04x", gpu_info.gpu.vendor_id));
  base::debug::SetCrashKeyValue(gpu::crash_keys::kGPUDeviceID,
      base::StringPrintf("0x%04x", gpu_info.gpu.device_id));
  base::debug::SetCrashKeyValue(gpu::crash_keys::kGPUDriverVersion,
      gpu_info.driver_version);
  base::debug::SetCrashKeyValue(gpu::crash_keys::kGPUPixelShaderVersion,
      gpu_info.pixel_shader_version);
  base::debug::SetCrashKeyValue(gpu::crash_keys::kGPUVertexShaderVersion,
      gpu_info.vertex_shader_version);
#if defined(OS_MACOSX)
  base::debug::SetCrashKeyValue(gpu::crash_keys::kGPUGLVersion,
      gpu_info.gl_version);
#elif defined(OS_POSIX)
  base::debug::SetCrashKeyValue(gpu::crash_keys::kGPUVendor,
      gpu_info.gl_vendor);
  base::debug::SetCrashKeyValue(gpu::crash_keys::kGPURenderer,
      gpu_info.gl_renderer);
#endif
}

std::string AtomContentClient::GetProduct() const {
  return "Chrome/" CHROME_VERSION_STRING;
}

std::string AtomContentClient::GetUserAgent() const {
  return content::BuildUserAgentFromProduct(
      "Chrome/" CHROME_VERSION_STRING);
}

bool AtomContentClient::IsSupplementarySiteIsolationModeEnabled() {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  return extensions::IsIsolateExtensionsEnabled();
#else
  return false;
#endif
}

void AtomContentClient::AddAdditionalSchemes(Schemes* schemes) {
  schemes->standard_schemes.push_back(extensions::kExtensionScheme);
  schemes->savable_schemes.push_back(extensions::kExtensionScheme);
  schemes->secure_schemes.push_back(extensions::kExtensionScheme);
  schemes->secure_origins = GetSecureOriginWhitelist();

#if BUILDFLAG(ENABLE_EXTENSIONS)
  if (extensions::feature_util::ExtensionServiceWorkersEnabled())
    schemes->service_worker_schemes.push_back(extensions::kExtensionScheme);

  // As far as Blink is concerned, they should be allowed to receive CORS
  // requests. At the Extensions layer, requests will actually be blocked unless
  // overridden by the web_accessible_resources manifest key.
  // TODO(kalman): See what happens with a service worker.
  schemes->cors_enabled_schemes.push_back(extensions::kExtensionScheme);
#endif
}

bool AtomContentClient::AllowScriptExtensionForServiceWorker(
    const GURL& script_url) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  return script_url.SchemeIs(extensions::kExtensionScheme);
#else
  return false;
#endif
}

content::OriginTrialPolicy* AtomContentClient::GetOriginTrialPolicy() {
  if (!origin_trial_policy_) {
    origin_trial_policy_ = base::WrapUnique(new ChromeOriginTrialPolicy());
  }
  return origin_trial_policy_.get();
}

void AtomContentClient::AddPepperPlugins(
    std::vector<content::PepperPluginInfo>* plugins) {
  AddPepperFlashFromCommandLine(plugins);
}

}  // namespace atom
<|endoftext|>