<commit_before>//===- lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp ---------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file \brief This file provides a way to read an import library member in a
/// .lib file.
///
/// Archive Files in Windows
/// ========================
///
/// In Windows, archive files with .lib file extension serve two different
/// purposes.
///
///  - For static linking: An archive file in this use case contains multiple
///    regular .obj files and is used for static linking. This is the same
///    usage as .a file in Unix.
///
///  - For dynamic linking: An archive file in this use case contains pseudo
///    .obj files to describe exported symbols of a DLL. Each pseudo .obj file
///    in an archive has a name of an exported symbol and a DLL filename from
///    which the symbol can be imported. When you link a DLL on Windows, you
///    pass the name of the .lib file for the DLL instead of the DLL filename
///    itself. That is the Windows way of linking against a shared library.
///
/// This file contains a function to handle the pseudo object file.
///
/// Windows Loader and Import Address Table
/// =======================================
///
/// Windows supports a GOT-like mechanism for DLLs. The executable using DLLs
/// contains a list of DLL names and list of symbols that need to be resolved by
/// the loader. Windows loader maps the executable and all the DLLs to memory,
/// resolves the symbols referencing items in DLLs, and updates the import
/// address table (IAT) in memory. The IAT is an array of pointers to all of the
/// data or functions in DLL referenced by the executable. You cannot access
/// items in DLLs directly. They have to be accessed through an extra level of
/// indirection.
///
/// So, if you want to access an item in DLL, you have to go through a
/// pointer. How do you actually do that? You need a symbol for a pointer in the
/// IAT. For each symbol defined in a DLL, a symbol with "__imp_" prefix is
/// exported from the DLL for an IAT entry. For example, if you have a global
/// variable "foo" in a DLL, a pointer to the variable is available as
/// "_imp__foo". The IAT is an array of _imp__ symbols.
///
/// Is this OK? That's not that complicated. Because items in a DLL are not
/// directly accessible, you need to access through a pointer, and the pointer
/// is available as a symbol with _imp__ prefix.
///
/// Note 1: Although you can write code with _imp__ prefix, today's compiler and
/// linker let you write code as if there's no extra level of indirection.
/// That's why you haven't seen lots of _imp__ in your code. A variable or a
/// function declared with "dllimport" attribute is treated as an item in a DLL,
/// and the compiler automatically mangles its name and inserts the extra level
/// of indirection when accessing the item. Here are some examples:
///
///   __declspec(dllimport) int var_in_dll;
///   var_in_dll = 3;  // is equivalent to *_imp__var_in_dll = 3;
///
///   __declspec(dllimport) int fn_in_dll(void);
///   fn_in_dll();     // is equivalent to (*_imp__fn_in_dll)();
///
/// It's just the compiler rewrites code for you so that you don't need to
/// handle the indirection youself.
///
/// Note 2: __declspec(dllimport) is mandatory for data but optional for
/// function. For a function, the linker creates a jump table with the original
/// symbol name, so that the function is accessible without _imp__ prefix. The
/// same function in a DLL can be called through two different symbols if it's
/// not dllimport'ed.
///
///   (*_imp__fn)()
///   fn()
///
/// The above functions do the same thing. fn's content is a JMP instruction to
/// branch to the address pointed by _imp__fn. The latter may be a little bit
/// slower than the former because it will execute the extra JMP instruction, but
/// that's usually negligible.
///
/// If a function is dllimport'ed, which is usually done in a header file,
/// mangled name will be used at compile time so the jump table will not be
/// used.
///
/// Because there's no way to hide the indirection for data access at link time,
/// data has to be accessed through dllimport'ed symbols or explicit _imp__
/// prefix.
///
/// Creating Atoms for the Import Address Table
/// ===========================================
///
/// The function in this file reads a pseudo object file and creates at most two
/// atoms. One is a shared library atom for _imp__ symbol. The another is a
/// defined atom for the JMP instruction if the symbol is for a function.
///
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "ReaderImportHeader"

#include "Atoms.h"

#include "lld/Core/File.h"
#include "lld/Core/Error.h"
#include "lld/Core/SharedLibraryAtom.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"

#include <map>
#include <vector>
#include <cstring>

using namespace lld;
using namespace llvm;

namespace lld {
namespace coff {

namespace {

/// The defined atom for jump table.
class FuncAtom : public COFFLinkerInternalAtom {
public:
  FuncAtom(const File &file, StringRef symbolName)
      : COFFLinkerInternalAtom(file, std::vector<uint8_t>(rawContent),
                               symbolName) {}

  virtual uint64_t ordinal() const { return 0; }
  virtual Scope scope() const { return scopeGlobal; }
  virtual ContentType contentType() const { return typeCode; }
  virtual Alignment alignment() const { return Alignment(1); }
  virtual ContentPermissions permissions() const { return permR_X; }

private:
  static std::vector<uint8_t> rawContent;
};

// MSVC doesn't seem to like C++11 initializer list, so initialize the
// vector from an array.
namespace {
uint8_t FuncAtomContent[] = {
  0xff, 0x25, 0x00, 0x00, 0x00, 0x00,  // jmp *0x0
  0x90, 0x90                           // nop; nop
};
} // anonymous namespace

std::vector<uint8_t> FuncAtom::rawContent(
    FuncAtomContent, FuncAtomContent + sizeof(FuncAtomContent));

class FileImportLibrary : public File {
public:
  FileImportLibrary(const TargetInfo &ti,
                    std::unique_ptr<llvm::MemoryBuffer> mb,
                    llvm::error_code &ec)
      : File(mb->getBufferIdentifier(), kindSharedLibrary), _targetInfo(ti) {
    const char *buf = mb->getBufferStart();
    const char *end = mb->getBufferEnd();

    // The size of the string that follows the header.
    uint32_t dataSize = *reinterpret_cast<const support::ulittle32_t *>(
        buf + offsetof(COFF::ImportHeader, SizeOfData));

    // Check if the total size is valid.
    if (end - buf != sizeof(COFF::ImportHeader) + dataSize) {
      ec = make_error_code(native_reader_error::unknown_file_format);
      return;
    }

    uint16_t hint = *reinterpret_cast<const support::ulittle16_t *>(
        buf + offsetof(COFF::ImportHeader, OrdinalHint));
    StringRef symbolName(buf + sizeof(COFF::ImportHeader));
    StringRef dllName(buf + sizeof(COFF::ImportHeader) + symbolName.size() + 1);

    // TypeInfo is a bitfield. The least significant 2 bits are import
    // type, followed by 3 bit import name type.
    uint16_t typeInfo = *reinterpret_cast<const support::ulittle16_t *>(
        buf + offsetof(COFF::ImportHeader, TypeInfo));
    int type = typeInfo & 0x3;
    int nameType = (typeInfo >> 2) & 0x7;

    // Symbol name used by the linker may be different from the symbol name used
    // by the loader. The latter may lack symbol decorations, or may not even
    // have name if it's imported by ordinal.
    StringRef importName = symbolNameToImportName(symbolName, nameType);

    const COFFSharedLibraryAtom *dataAtom = addSharedLibraryAtom(
        hint, symbolName, importName, dllName);
    if (type == llvm::COFF::IMPORT_CODE)
      addDefinedAtom(symbolName, dllName, dataAtom);

    ec = error_code::success();
  }

  virtual const atom_collection<DefinedAtom> &defined() const {
    return _definedAtoms;
  }

  virtual const atom_collection<UndefinedAtom> &undefined() const {
    return _noUndefinedAtoms;
  }

  virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
    return _sharedLibraryAtoms;
  }

  virtual const atom_collection<AbsoluteAtom> &absolute() const {
    return _noAbsoluteAtoms;
  }

  virtual const TargetInfo &getTargetInfo() const { return _targetInfo; }

private:
  const COFFSharedLibraryAtom *
  addSharedLibraryAtom(uint16_t hint, StringRef symbolName,
                       StringRef importName, StringRef dllName) {
    auto *atom = new (_alloc) COFFSharedLibraryAtom(
        *this, hint, symbolName, importName, dllName);
    _sharedLibraryAtoms._atoms.push_back(atom);
    return atom;
  }

  void addDefinedAtom(StringRef symbolName, StringRef dllName,
                      const COFFSharedLibraryAtom *dataAtom) {
    auto *atom = new (_alloc) FuncAtom(*this, symbolName);

    // The first two byte of the atom is JMP instruction.
    atom->addReference(std::unique_ptr<COFFReference>(
        new COFFReference(dataAtom, 2, llvm::COFF::IMAGE_REL_I386_DIR32)));
    _definedAtoms._atoms.push_back(atom);
  }

  atom_collection_vector<DefinedAtom> _definedAtoms;
  atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
  const TargetInfo &_targetInfo;
  mutable llvm::BumpPtrAllocator _alloc;

  // Convert the given symbol name to the import symbol name exported by the
  // DLL.
  StringRef symbolNameToImportName(StringRef symbolName, int nameType) const {
    StringRef ret;
    switch (nameType) {
    case llvm::COFF::IMPORT_ORDINAL:
      // The import is by ordinal. No symbol name will be used to identify the
      // item in the DLL. Only its ordinal will be used.
      return "";
    case llvm::COFF::IMPORT_NAME:
      // The import name in this case is identical to the symbol name.
      return symbolName;
    case llvm::COFF::IMPORT_NAME_NOPREFIX:
      // The import name is the symbol name without leading ?, @ or _.
      ret = symbolName.ltrim("?@_");
      break;
    case llvm::COFF::IMPORT_NAME_UNDECORATE:
      // Similar to NOPREFIX, but we also need to truncate at the first @.
      ret = symbolName.ltrim("?@_");
      ret = ret.substr(0, ret.find('@'));
      break;
    }
    std::string *str = new (_alloc) std::string(ret);
    return *str;
  }
};

} // end anonymous namespace

error_code parseCOFFImportLibrary(const TargetInfo &targetInfo,
                                  std::unique_ptr<MemoryBuffer> &mb,
                                  std::vector<std::unique_ptr<File> > &result) {
  // Check the file magic.
  const char *buf = mb->getBufferStart();
  const char *end = mb->getBufferEnd();
  // Error if the file is too small or does not start with the magic.
  if (end - buf < static_cast<ptrdiff_t>(sizeof(COFF::ImportHeader)) ||
      memcmp(buf, "\0\0\xFF\xFF", 4))
    return make_error_code(native_reader_error::unknown_file_format);

  error_code ec;
  auto file = std::unique_ptr<File>(
      new FileImportLibrary(targetInfo, std::move(mb), ec));
  if (ec)
    return ec;
  result.push_back(std::move(file));
  return error_code::success();
}

} // end namespace coff
} // end namespace lld
<commit_msg>[PECOFF] Add a comment on the idata section fragments.<commit_after>//===- lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp ---------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file \brief This file provides a way to read an import library member in a
/// .lib file.
///
/// Archive Files in Windows
/// ========================
///
/// In Windows, archive files with .lib file extension serve two different
/// purposes.
///
///  - For static linking: An archive file in this use case contains multiple
///    regular .obj files and is used for static linking. This is the same
///    usage as .a file in Unix.
///
///  - For dynamic linking: An archive file in this use case contains pseudo
///    .obj files to describe exported symbols of a DLL. Each pseudo .obj file
///    in an archive has a name of an exported symbol and a DLL filename from
///    which the symbol can be imported. When you link a DLL on Windows, you
///    pass the name of the .lib file for the DLL instead of the DLL filename
///    itself. That is the Windows way of linking against a shared library.
///
/// This file contains a function to handle the pseudo object file.
///
/// Windows Loader and Import Address Table
/// =======================================
///
/// Windows supports a GOT-like mechanism for DLLs. The executable using DLLs
/// contains a list of DLL names and list of symbols that need to be resolved by
/// the loader. Windows loader maps the executable and all the DLLs to memory,
/// resolves the symbols referencing items in DLLs, and updates the import
/// address table (IAT) in memory. The IAT is an array of pointers to all of the
/// data or functions in DLL referenced by the executable. You cannot access
/// items in DLLs directly. They have to be accessed through an extra level of
/// indirection.
///
/// So, if you want to access an item in DLL, you have to go through a
/// pointer. How do you actually do that? You need a symbol for a pointer in the
/// IAT. For each symbol defined in a DLL, a symbol with "__imp_" prefix is
/// exported from the DLL for an IAT entry. For example, if you have a global
/// variable "foo" in a DLL, a pointer to the variable is available as
/// "_imp__foo". The IAT is an array of _imp__ symbols.
///
/// Is this OK? That's not that complicated. Because items in a DLL are not
/// directly accessible, you need to access through a pointer, and the pointer
/// is available as a symbol with _imp__ prefix.
///
/// Note 1: Although you can write code with _imp__ prefix, today's compiler and
/// linker let you write code as if there's no extra level of indirection.
/// That's why you haven't seen lots of _imp__ in your code. A variable or a
/// function declared with "dllimport" attribute is treated as an item in a DLL,
/// and the compiler automatically mangles its name and inserts the extra level
/// of indirection when accessing the item. Here are some examples:
///
///   __declspec(dllimport) int var_in_dll;
///   var_in_dll = 3;  // is equivalent to *_imp__var_in_dll = 3;
///
///   __declspec(dllimport) int fn_in_dll(void);
///   fn_in_dll();     // is equivalent to (*_imp__fn_in_dll)();
///
/// It's just the compiler rewrites code for you so that you don't need to
/// handle the indirection youself.
///
/// Note 2: __declspec(dllimport) is mandatory for data but optional for
/// function. For a function, the linker creates a jump table with the original
/// symbol name, so that the function is accessible without _imp__ prefix. The
/// same function in a DLL can be called through two different symbols if it's
/// not dllimport'ed.
///
///   (*_imp__fn)()
///   fn()
///
/// The above functions do the same thing. fn's content is a JMP instruction to
/// branch to the address pointed by _imp__fn. The latter may be a little bit
/// slower than the former because it will execute the extra JMP instruction, but
/// that's usually negligible.
///
/// If a function is dllimport'ed, which is usually done in a header file,
/// mangled name will be used at compile time so the jump table will not be
/// used.
///
/// Because there's no way to hide the indirection for data access at link time,
/// data has to be accessed through dllimport'ed symbols or explicit _imp__
/// prefix.
///
/// Idata Sections in the Pseudo Object File
/// ========================================
///
/// The object file created by cl.exe has several sections whose name starts
/// with ".idata$" followed by a number. The contents of the sections seem the
/// fragments of a complete ".idata" section. These sections has relocations for
/// the data referenced from the idata secton. Generally, the linker discards
/// "$" and all characters that follow from the section name and merges their
/// contents to one section. So, it looks like if everything would work fine,
/// the idata section would naturally be constructed without having any special
/// code for doing that.
///
/// However, the LLD linker cannot do that. An idata section constructed in that
/// way was never be in valid format. We don't know the reason yet. Our
/// assumption on the idata fragment could simply be wrong, or the LLD linker is
/// not powerful enough to do the job. Meanwhile, we construct the idata section
/// ourselves. All the "idata$" sections in the pseudo object file are currently
/// ignored.
///
/// Creating Atoms for the Import Address Table
/// ===========================================
///
/// The function in this file reads a pseudo object file and creates at most two
/// atoms. One is a shared library atom for _imp__ symbol. The another is a
/// defined atom for the JMP instruction if the symbol is for a function.
///
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "ReaderImportHeader"

#include "Atoms.h"

#include "lld/Core/File.h"
#include "lld/Core/Error.h"
#include "lld/Core/SharedLibraryAtom.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"

#include <map>
#include <vector>
#include <cstring>

using namespace lld;
using namespace llvm;

namespace lld {
namespace coff {

namespace {

/// The defined atom for jump table.
class FuncAtom : public COFFLinkerInternalAtom {
public:
  FuncAtom(const File &file, StringRef symbolName)
      : COFFLinkerInternalAtom(file, std::vector<uint8_t>(rawContent),
                               symbolName) {}

  virtual uint64_t ordinal() const { return 0; }
  virtual Scope scope() const { return scopeGlobal; }
  virtual ContentType contentType() const { return typeCode; }
  virtual Alignment alignment() const { return Alignment(1); }
  virtual ContentPermissions permissions() const { return permR_X; }

private:
  static std::vector<uint8_t> rawContent;
};

// MSVC doesn't seem to like C++11 initializer list, so initialize the
// vector from an array.
namespace {
uint8_t FuncAtomContent[] = {
  0xff, 0x25, 0x00, 0x00, 0x00, 0x00,  // jmp *0x0
  0x90, 0x90                           // nop; nop
};
} // anonymous namespace

std::vector<uint8_t> FuncAtom::rawContent(
    FuncAtomContent, FuncAtomContent + sizeof(FuncAtomContent));

class FileImportLibrary : public File {
public:
  FileImportLibrary(const TargetInfo &ti,
                    std::unique_ptr<llvm::MemoryBuffer> mb,
                    llvm::error_code &ec)
      : File(mb->getBufferIdentifier(), kindSharedLibrary), _targetInfo(ti) {
    const char *buf = mb->getBufferStart();
    const char *end = mb->getBufferEnd();

    // The size of the string that follows the header.
    uint32_t dataSize = *reinterpret_cast<const support::ulittle32_t *>(
        buf + offsetof(COFF::ImportHeader, SizeOfData));

    // Check if the total size is valid.
    if (end - buf != sizeof(COFF::ImportHeader) + dataSize) {
      ec = make_error_code(native_reader_error::unknown_file_format);
      return;
    }

    uint16_t hint = *reinterpret_cast<const support::ulittle16_t *>(
        buf + offsetof(COFF::ImportHeader, OrdinalHint));
    StringRef symbolName(buf + sizeof(COFF::ImportHeader));
    StringRef dllName(buf + sizeof(COFF::ImportHeader) + symbolName.size() + 1);

    // TypeInfo is a bitfield. The least significant 2 bits are import
    // type, followed by 3 bit import name type.
    uint16_t typeInfo = *reinterpret_cast<const support::ulittle16_t *>(
        buf + offsetof(COFF::ImportHeader, TypeInfo));
    int type = typeInfo & 0x3;
    int nameType = (typeInfo >> 2) & 0x7;

    // Symbol name used by the linker may be different from the symbol name used
    // by the loader. The latter may lack symbol decorations, or may not even
    // have name if it's imported by ordinal.
    StringRef importName = symbolNameToImportName(symbolName, nameType);

    const COFFSharedLibraryAtom *dataAtom = addSharedLibraryAtom(
        hint, symbolName, importName, dllName);
    if (type == llvm::COFF::IMPORT_CODE)
      addDefinedAtom(symbolName, dllName, dataAtom);

    ec = error_code::success();
  }

  virtual const atom_collection<DefinedAtom> &defined() const {
    return _definedAtoms;
  }

  virtual const atom_collection<UndefinedAtom> &undefined() const {
    return _noUndefinedAtoms;
  }

  virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
    return _sharedLibraryAtoms;
  }

  virtual const atom_collection<AbsoluteAtom> &absolute() const {
    return _noAbsoluteAtoms;
  }

  virtual const TargetInfo &getTargetInfo() const { return _targetInfo; }

private:
  const COFFSharedLibraryAtom *
  addSharedLibraryAtom(uint16_t hint, StringRef symbolName,
                       StringRef importName, StringRef dllName) {
    auto *atom = new (_alloc) COFFSharedLibraryAtom(
        *this, hint, symbolName, importName, dllName);
    _sharedLibraryAtoms._atoms.push_back(atom);
    return atom;
  }

  void addDefinedAtom(StringRef symbolName, StringRef dllName,
                      const COFFSharedLibraryAtom *dataAtom) {
    auto *atom = new (_alloc) FuncAtom(*this, symbolName);

    // The first two byte of the atom is JMP instruction.
    atom->addReference(std::unique_ptr<COFFReference>(
        new COFFReference(dataAtom, 2, llvm::COFF::IMAGE_REL_I386_DIR32)));
    _definedAtoms._atoms.push_back(atom);
  }

  atom_collection_vector<DefinedAtom> _definedAtoms;
  atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
  const TargetInfo &_targetInfo;
  mutable llvm::BumpPtrAllocator _alloc;

  // Convert the given symbol name to the import symbol name exported by the
  // DLL.
  StringRef symbolNameToImportName(StringRef symbolName, int nameType) const {
    StringRef ret;
    switch (nameType) {
    case llvm::COFF::IMPORT_ORDINAL:
      // The import is by ordinal. No symbol name will be used to identify the
      // item in the DLL. Only its ordinal will be used.
      return "";
    case llvm::COFF::IMPORT_NAME:
      // The import name in this case is identical to the symbol name.
      return symbolName;
    case llvm::COFF::IMPORT_NAME_NOPREFIX:
      // The import name is the symbol name without leading ?, @ or _.
      ret = symbolName.ltrim("?@_");
      break;
    case llvm::COFF::IMPORT_NAME_UNDECORATE:
      // Similar to NOPREFIX, but we also need to truncate at the first @.
      ret = symbolName.ltrim("?@_");
      ret = ret.substr(0, ret.find('@'));
      break;
    }
    std::string *str = new (_alloc) std::string(ret);
    return *str;
  }
};

} // end anonymous namespace

error_code parseCOFFImportLibrary(const TargetInfo &targetInfo,
                                  std::unique_ptr<MemoryBuffer> &mb,
                                  std::vector<std::unique_ptr<File> > &result) {
  // Check the file magic.
  const char *buf = mb->getBufferStart();
  const char *end = mb->getBufferEnd();
  // Error if the file is too small or does not start with the magic.
  if (end - buf < static_cast<ptrdiff_t>(sizeof(COFF::ImportHeader)) ||
      memcmp(buf, "\0\0\xFF\xFF", 4))
    return make_error_code(native_reader_error::unknown_file_format);

  error_code ec;
  auto file = std::unique_ptr<File>(
      new FileImportLibrary(targetInfo, std::move(mb), ec));
  if (ec)
    return ec;
  result.push_back(std::move(file));
  return error_code::success();
}

} // end namespace coff
} // end namespace lld
<|endoftext|>


<commit_before>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <coecntrl.h> // for CCoeControl

#include <QApplication>    // for QApplication::activeWindow
#include <QtCore/private/qcore_symbian_p.h> // for qt_TRect2QRect

#include "utils.h"
#include "videooutput_dsa.h"
#include "videoplayer_dsa.h"

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

// Two-phase constructor idiom is used because construct() calls virtual
// functions and therefore cannot be called from the AbstractVideoPlayer
// C++ constructor.
DsaVideoPlayer* DsaVideoPlayer::create(MediaObject *parent,
                                       const AbstractPlayer *player)
{
    QScopedPointer<DsaVideoPlayer> self(new DsaVideoPlayer(parent, player));
    self->construct();
    return self.take();
}

DsaVideoPlayer::DsaVideoPlayer(MediaObject *parent, const AbstractPlayer *player)
    :   AbstractVideoPlayer(parent, player)
    ,   m_dsaActive(false)
    ,   m_dsaWasActive(false)
{

}

DsaVideoPlayer::~DsaVideoPlayer()
{

}

//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------

void MMF::DsaVideoPlayer::videoWindowScreenRectChanged()
{
    QRect windowRect = static_cast<DsaVideoOutput *>(m_videoOutput)->videoWindowScreenRect();

    // Clip to physical window size
    // This is due to a defect in the layout when running on S60 3.2, which
    // results in the rectangle of the video widget extending outside the
    // screen in certain circumstances.  These include the initial startup
    // of the mediaplayer demo in portrait mode.  When this rectangle is
    // passed to the CVideoPlayerUtility, no video is rendered.
    const TSize screenSize = m_screenDevice.SizeInPixels();
    const QRect screenRect(0, 0, screenSize.iWidth, screenSize.iHeight);
    windowRect = windowRect.intersected(screenRect);

    // Recalculate scale factors.  Pass 'false' as second parameter in order to
    // suppress application of the change to the player - this is done at the end
    // of the function.
    updateScaleFactors(windowRect.size(), false);

    m_videoScreenRect = qt_QRect2TRect(windowRect);

    parametersChanged(WindowScreenRect | ScaleFactors);
}

void MMF::DsaVideoPlayer::suspendDirectScreenAccess()
{
    m_dsaWasActive = stopDirectScreenAccess();
}

void MMF::DsaVideoPlayer::resumeDirectScreenAccess()
{
    if (m_dsaWasActive) {
        startDirectScreenAccess();
        m_dsaWasActive = false;
    }
}

//-----------------------------------------------------------------------------
// Private functions
//-----------------------------------------------------------------------------

void MMF::DsaVideoPlayer::createPlayer()
{
    // A window handle must be provided in order to construct
    // CVideoPlayerUtility.  If no VideoOutput has yet been connected to this
    // player, we temporarily use the top-level application window handle.
    // No video ever gets rendered into this window; SetDisplayWindowL is
    // always called before rendering actually begins.
    if (!m_window)
        m_window = QApplication::activeWindow()->effectiveWinId()->DrawableWindow();

    const TInt priority = 0;
    const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone;

    CVideoPlayerUtility *player = 0;
    QT_TRAP_THROWING(player = CVideoPlayerUtility::NewL(*this,
                                     priority, preference,
                                     m_wsSession, m_screenDevice,
                                     *m_window,
                                     m_videoScreenRect, m_videoScreenRect));
    m_player.reset(player);

    // CVideoPlayerUtility::NewL starts DSA
    m_dsaActive = true;

    m_player->RegisterForVideoLoadingNotification(*this);
}

void MMF::DsaVideoPlayer::initVideoOutput()
{
    bool connected = connect(
        m_videoOutput, SIGNAL(videoWindowScreenRectChanged()),
        this, SLOT(videoWindowScreenRectChanged())
    );
    Q_ASSERT(connected);

    connected = connect(
        m_videoOutput, SIGNAL(beginVideoWindowNativePaint()),
        this, SLOT(suspendDirectScreenAccess())
    );
    Q_ASSERT(connected);

    connected = connect(
        m_videoOutput, SIGNAL(endVideoWindowNativePaint()),
        this, SLOT(resumeDirectScreenAccess())
    );
    Q_ASSERT(connected);

    // Suppress warnings in release builds
    Q_UNUSED(connected);

    AbstractVideoPlayer::initVideoOutput();
}

void MMF::DsaVideoPlayer::prepareCompleted()
{
    videoWindowScreenRectChanged();
}

void MMF::DsaVideoPlayer::handleVideoWindowChanged()
{
    if (!m_window) {
        if (QWidget *window = QApplication::activeWindow())
            m_window = window->effectiveWinId()->DrawableWindow();
        else
            m_window = 0;
        m_videoScreenRect = TRect();
    }

    parametersChanged(WindowHandle | WindowScreenRect);
}

#ifndef QT_NO_DEBUG

// The following code is for debugging problems related to video visibility.  It allows
// the VideoPlayer instance to query the window server in order to determine the
// DSA drawing region for the video window.

class CDummyAO : public CActive
{
public:
    CDummyAO() : CActive(CActive::EPriorityStandard) { CActiveScheduler::Add(this); }
    void RunL() { }
    void DoCancel() { }
    TRequestStatus& Status() { return iStatus; }
    void SetActive() { CActive::SetActive(); }
};

void getDsaRegion(RWsSession &session, const RWindowBase &window)
{
    // Dump complete window tree
    session.LogCommand(RWsSession::ELoggingStatusDump);

    RDirectScreenAccess dsa(session);
    TInt err = dsa.Construct();
    CDummyAO ao;
    RRegion* region;
    err = dsa.Request(region, ao.Status(), window);
    ao.SetActive();
    dsa.Close();
    ao.Cancel();
    if (region) {
        qDebug() << "Phonon::MMF::getDsaRegion count" << region->Count();
        for (int i=0; i<region->Count(); ++i) {
            const TRect& rect = region->RectangleList()[i];
            qDebug() << "Phonon::MMF::getDsaRegion rect"
                << rect.iTl.iX << rect.iTl.iY << rect.iBr.iX << rect.iBr.iY;
        }
        region->Close();
    }
}

#endif // QT_NO_DEBUG

void MMF::DsaVideoPlayer::handleParametersChanged(VideoParameters parameters)
{
    TRACE_CONTEXT(DsaVideoPlayer::handleParametersChanged, EVideoInternal);
    TRACE_ENTRY("parameters 0x%x", parameters.operator int());

    if (!m_window)
        return;

#ifndef QT_NO_DEBUG
    getDsaRegion(m_wsSession, *m_window);
#endif

    static const TBool antialias = ETrue;
    int err = KErrNone;

    if (parameters & ScaleFactors) {
        TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
                                            antialias));
        if(KErrNone != err) {
            TRACE("SetScaleFactorL (1) err %d", err);
            setError(tr("Video display error"), err);
        }
    }

    if (KErrNone == err) {
        if (parameters & WindowHandle || parameters & WindowScreenRect) {
            TRAP(err,
                m_player->SetDisplayWindowL(m_wsSession, m_screenDevice,
                                            *m_window,
                                            m_videoScreenRect,
                                            m_videoScreenRect));
        }

        if (KErrNone != err) {
            TRACE("SetDisplayWindowL err %d", err);
            setError(tr("Video display error"), err);
        } else {
            m_dsaActive = true;
            if (parameters & ScaleFactors) {
                TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
                                                    antialias));
                if (KErrNone != err) {
                    TRACE("SetScaleFactorL (2) err %d", err);
                    setError(tr("Video display error"), err);
                }
            }
        }
    }

    TRACE_EXIT_0();
}

void MMF::DsaVideoPlayer::startDirectScreenAccess()
{
    TRACE_CONTEXT(DsaVideoPlayer::startDirectScreenAccess, EVideoInternal);
    TRACE_ENTRY("dsaActive %d", m_dsaActive);

    int err = KErrNone;

    if (!m_dsaActive) {
        TRAP(err, m_player->StartDirectScreenAccessL());
        if (KErrNone == err)
            m_dsaActive = true;
        else
            setError(tr("Video display error"), err);
    }

    if (m_videoOutput)
        m_videoOutput->dump();

    TRACE_EXIT("error %d", err);
}

bool MMF::DsaVideoPlayer::stopDirectScreenAccess()
{
    TRACE_CONTEXT(DsaVideoPlayer::stopDirectScreenAccess, EVideoInternal);
    TRACE_ENTRY("dsaActive %d", m_dsaActive);

    int err = KErrNone;

    const bool dsaWasActive = m_dsaActive;
    if (m_dsaActive) {
        TRAPD(err, m_player->StopDirectScreenAccessL());
        if (KErrNone == err)
            m_dsaActive = false;
        else
            setError(tr("Video display error"), err);
    }

    TRACE_EXIT("error %d", err);

    return dsaWasActive;
}

QT_END_NAMESPACE

<commit_msg>Phonon MMF: Removed compiler warning<commit_after>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <coecntrl.h> // for CCoeControl

#include <QApplication>    // for QApplication::activeWindow
#include <QtCore/private/qcore_symbian_p.h> // for qt_TRect2QRect

#include "utils.h"
#include "videooutput_dsa.h"
#include "videoplayer_dsa.h"

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

// Two-phase constructor idiom is used because construct() calls virtual
// functions and therefore cannot be called from the AbstractVideoPlayer
// C++ constructor.
DsaVideoPlayer* DsaVideoPlayer::create(MediaObject *parent,
                                       const AbstractPlayer *player)
{
    QScopedPointer<DsaVideoPlayer> self(new DsaVideoPlayer(parent, player));
    self->construct();
    return self.take();
}

DsaVideoPlayer::DsaVideoPlayer(MediaObject *parent, const AbstractPlayer *player)
    :   AbstractVideoPlayer(parent, player)
    ,   m_dsaActive(false)
    ,   m_dsaWasActive(false)
{

}

DsaVideoPlayer::~DsaVideoPlayer()
{

}

//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------

void MMF::DsaVideoPlayer::videoWindowScreenRectChanged()
{
    QRect windowRect = static_cast<DsaVideoOutput *>(m_videoOutput)->videoWindowScreenRect();

    // Clip to physical window size
    // This is due to a defect in the layout when running on S60 3.2, which
    // results in the rectangle of the video widget extending outside the
    // screen in certain circumstances.  These include the initial startup
    // of the mediaplayer demo in portrait mode.  When this rectangle is
    // passed to the CVideoPlayerUtility, no video is rendered.
    const TSize screenSize = m_screenDevice.SizeInPixels();
    const QRect screenRect(0, 0, screenSize.iWidth, screenSize.iHeight);
    windowRect = windowRect.intersected(screenRect);

    // Recalculate scale factors.  Pass 'false' as second parameter in order to
    // suppress application of the change to the player - this is done at the end
    // of the function.
    updateScaleFactors(windowRect.size(), false);

    m_videoScreenRect = qt_QRect2TRect(windowRect);

    parametersChanged(WindowScreenRect | ScaleFactors);
}

void MMF::DsaVideoPlayer::suspendDirectScreenAccess()
{
    m_dsaWasActive = stopDirectScreenAccess();
}

void MMF::DsaVideoPlayer::resumeDirectScreenAccess()
{
    if (m_dsaWasActive) {
        startDirectScreenAccess();
        m_dsaWasActive = false;
    }
}

//-----------------------------------------------------------------------------
// Private functions
//-----------------------------------------------------------------------------

void MMF::DsaVideoPlayer::createPlayer()
{
    // A window handle must be provided in order to construct
    // CVideoPlayerUtility.  If no VideoOutput has yet been connected to this
    // player, we temporarily use the top-level application window handle.
    // No video ever gets rendered into this window; SetDisplayWindowL is
    // always called before rendering actually begins.
    if (!m_window)
        m_window = QApplication::activeWindow()->effectiveWinId()->DrawableWindow();

    const TInt priority = 0;
    const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone;

    CVideoPlayerUtility *player = 0;
    QT_TRAP_THROWING(player = CVideoPlayerUtility::NewL(*this,
                                     priority, preference,
                                     m_wsSession, m_screenDevice,
                                     *m_window,
                                     m_videoScreenRect, m_videoScreenRect));
    m_player.reset(player);

    // CVideoPlayerUtility::NewL starts DSA
    m_dsaActive = true;

    m_player->RegisterForVideoLoadingNotification(*this);
}

void MMF::DsaVideoPlayer::initVideoOutput()
{
    bool connected = connect(
        m_videoOutput, SIGNAL(videoWindowScreenRectChanged()),
        this, SLOT(videoWindowScreenRectChanged())
    );
    Q_ASSERT(connected);

    connected = connect(
        m_videoOutput, SIGNAL(beginVideoWindowNativePaint()),
        this, SLOT(suspendDirectScreenAccess())
    );
    Q_ASSERT(connected);

    connected = connect(
        m_videoOutput, SIGNAL(endVideoWindowNativePaint()),
        this, SLOT(resumeDirectScreenAccess())
    );
    Q_ASSERT(connected);

    // Suppress warnings in release builds
    Q_UNUSED(connected);

    AbstractVideoPlayer::initVideoOutput();
}

void MMF::DsaVideoPlayer::prepareCompleted()
{
    videoWindowScreenRectChanged();
}

void MMF::DsaVideoPlayer::handleVideoWindowChanged()
{
    if (!m_window) {
        if (QWidget *window = QApplication::activeWindow())
            m_window = window->effectiveWinId()->DrawableWindow();
        else
            m_window = 0;
        m_videoScreenRect = TRect();
    }

    parametersChanged(WindowHandle | WindowScreenRect);
}

#ifndef QT_NO_DEBUG

// The following code is for debugging problems related to video visibility.  It allows
// the VideoPlayer instance to query the window server in order to determine the
// DSA drawing region for the video window.

class CDummyAO : public CActive
{
public:
    CDummyAO() : CActive(CActive::EPriorityStandard) { CActiveScheduler::Add(this); }
    void RunL() { }
    void DoCancel() { }
    TRequestStatus& Status() { return iStatus; }
    void SetActive() { CActive::SetActive(); }
};

void getDsaRegion(RWsSession &session, const RWindowBase &window)
{
    // Dump complete window tree
    session.LogCommand(RWsSession::ELoggingStatusDump);

    RDirectScreenAccess dsa(session);
    TInt err = dsa.Construct();
    CDummyAO ao;
    RRegion* region;
    err = dsa.Request(region, ao.Status(), window);
    ao.SetActive();
    dsa.Close();
    ao.Cancel();
    if (region) {
        qDebug() << "Phonon::MMF::getDsaRegion count" << region->Count();
        for (int i=0; i<region->Count(); ++i) {
            const TRect& rect = region->RectangleList()[i];
            qDebug() << "Phonon::MMF::getDsaRegion rect"
                << rect.iTl.iX << rect.iTl.iY << rect.iBr.iX << rect.iBr.iY;
        }
        region->Close();
    }
}

#endif // QT_NO_DEBUG

void MMF::DsaVideoPlayer::handleParametersChanged(VideoParameters parameters)
{
    TRACE_CONTEXT(DsaVideoPlayer::handleParametersChanged, EVideoInternal);
    TRACE_ENTRY("parameters 0x%x", parameters.operator int());

    if (!m_window)
        return;

#ifndef QT_NO_DEBUG
    getDsaRegion(m_wsSession, *m_window);
#endif

    static const TBool antialias = ETrue;
    int err = KErrNone;

    if (parameters & ScaleFactors) {
        TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
                                            antialias));
        if(KErrNone != err) {
            TRACE("SetScaleFactorL (1) err %d", err);
            setError(tr("Video display error"), err);
        }
    }

    if (KErrNone == err) {
        if (parameters & WindowHandle || parameters & WindowScreenRect) {
            TRAP(err,
                m_player->SetDisplayWindowL(m_wsSession, m_screenDevice,
                                            *m_window,
                                            m_videoScreenRect,
                                            m_videoScreenRect));
        }

        if (KErrNone != err) {
            TRACE("SetDisplayWindowL err %d", err);
            setError(tr("Video display error"), err);
        } else {
            m_dsaActive = true;
            if (parameters & ScaleFactors) {
                TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
                                                    antialias));
                if (KErrNone != err) {
                    TRACE("SetScaleFactorL (2) err %d", err);
                    setError(tr("Video display error"), err);
                }
            }
        }
    }

    TRACE_EXIT_0();
}

void MMF::DsaVideoPlayer::startDirectScreenAccess()
{
    TRACE_CONTEXT(DsaVideoPlayer::startDirectScreenAccess, EVideoInternal);
    TRACE_ENTRY("dsaActive %d", m_dsaActive);

    int err = KErrNone;

    if (!m_dsaActive) {
        TRAP(err, m_player->StartDirectScreenAccessL());
        if (KErrNone == err)
            m_dsaActive = true;
        else
            setError(tr("Video display error"), err);
    }

    if (m_videoOutput)
        m_videoOutput->dump();

    TRACE_EXIT("error %d", err);
}

bool MMF::DsaVideoPlayer::stopDirectScreenAccess()
{
    TRACE_CONTEXT(DsaVideoPlayer::stopDirectScreenAccess, EVideoInternal);
    TRACE_ENTRY("dsaActive %d", m_dsaActive);

    int err = KErrNone;

    const bool dsaWasActive = m_dsaActive;
    if (m_dsaActive) {
        TRAP(err, m_player->StopDirectScreenAccessL());
        if (KErrNone == err)
            m_dsaActive = false;
        else
            setError(tr("Video display error"), err);
    }

    TRACE_EXIT("error %d", err);

    return dsaWasActive;
}

QT_END_NAMESPACE

<|endoftext|>


<commit_before>#include "Genes/Opponent_Pieces_Targeted_Gene.h"

#include <array>
#include <memory>

#include "Game/Board.h"
#include "Pieces/Piece.h"
#include "Moves/Move.h"
#include "Genes/Gene.h"
#include "Genes/Piece_Strength_Gene.h"

Opponent_Pieces_Targeted_Gene::Opponent_Pieces_Targeted_Gene(const Piece_Strength_Gene* piece_strength_gene) :
    piece_strenth_source(piece_strength_gene)
{
}

double Opponent_Pieces_Targeted_Gene::score_board(const Board& board) const
{
    double score = 0.0;
    std::array<bool, 64> already_counted{};

    for(const auto& move : board.legal_moves())
    {
        if( ! move->can_capture())
        {
            continue;
        }
        auto end_file = move->end_file();
        auto end_rank = move->end_rank();
        if(move->is_en_passant())
        {
            end_rank -= move->rank_change();
        }
        auto target_piece = board.piece_on_square(end_file, end_rank);
        auto target_index = Board::board_index(end_file, end_rank);
        if(target_piece && ! already_counted[target_index])
        {
            score += piece_strenth_source->piece_value(target_piece);
            already_counted[target_index] = true;
        }
    }

    return score;
}

std::unique_ptr<Gene> Opponent_Pieces_Targeted_Gene::duplicate() const
{
    return std::make_unique<Opponent_Pieces_Targeted_Gene>(*this);
}

std::string Opponent_Pieces_Targeted_Gene::name() const
{
    return "Opponent Pieces Targeted Gene";
}

void Opponent_Pieces_Targeted_Gene::reset_piece_strength_gene(const Piece_Strength_Gene* psg)
{
    piece_strenth_source = psg;
}
<commit_msg>Fix Opponent Pieces Targeted Gene<commit_after>#include "Genes/Opponent_Pieces_Targeted_Gene.h"

#include <array>
#include <memory>

#include "Game/Board.h"
#include "Pieces/Piece.h"
#include "Pieces/Piece_Types.h"
#include "Moves/Move.h"
#include "Genes/Gene.h"
#include "Genes/Piece_Strength_Gene.h"

Opponent_Pieces_Targeted_Gene::Opponent_Pieces_Targeted_Gene(const Piece_Strength_Gene* piece_strength_gene) :
    piece_strenth_source(piece_strength_gene)
{
}

double Opponent_Pieces_Targeted_Gene::score_board(const Board& board) const
{
    double score = 0.0;
    std::array<bool, 64> already_counted{};

    for(const auto& move : board.legal_moves())
    {
        if(move->is_en_passant())
        {
            score += piece_strenth_source->piece_value(board.get_piece(PAWN, opposite(board.whose_turn())));
            continue;
        }

        if( ! move->can_capture())
        {
            continue;
        }

        auto end_file = move->end_file();
        auto end_rank = move->end_rank();
        auto target_piece = board.piece_on_square(end_file, end_rank);
        auto target_index = Board::board_index(end_file, end_rank);
        if(target_piece && ! already_counted[target_index])
        {
            score += piece_strenth_source->piece_value(target_piece);
            already_counted[target_index] = true;
        }
    }

    return score;
}

std::unique_ptr<Gene> Opponent_Pieces_Targeted_Gene::duplicate() const
{
    return std::make_unique<Opponent_Pieces_Targeted_Gene>(*this);
}

std::string Opponent_Pieces_Targeted_Gene::name() const
{
    return "Opponent Pieces Targeted Gene";
}

void Opponent_Pieces_Targeted_Gene::reset_piece_strength_gene(const Piece_Strength_Gene* psg)
{
    piece_strenth_source = psg;
}
<|endoftext|>


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

// This webpage shows layout of YV12 and other YUV formats
// http://www.fourcc.org/yuv.php
// The actual conversion is best described here
// http://en.wikipedia.org/wiki/YUV
// An article on optimizing YUV conversion using tables instead of multiplies
// http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
//
// YV12 is a full plane of Y and a half height, half width chroma planes
// YV16 is a full plane of Y and a full height, half width chroma planes
//
// ARGB pixel format is output, which on little endian is stored as BGRA.
// The alpha is set to 255, allowing the application to use RGBA or RGB32.

#include "media/base/yuv_convert.h"

// Header for low level row functions.
#include "media/base/yuv_row.h"

#if USE_MMX
#if defined(_MSC_VER)
#include <intrin.h>
#else
#include <mmintrin.h>
#endif
#endif

#if USE_SSE || USE_MMX
#include <emmintrin.h>
#endif

namespace media {

// 16.16 fixed point arithmetic.
const int kFractionBits = 16;
const int kFractionMax = 1 << kFractionBits;

// Convert a frame of YUV to 32 bit ARGB.
void ConvertYUVToRGB32(const uint8* y_buf,
                       const uint8* u_buf,
                       const uint8* v_buf,
                       uint8* rgb_buf,
                       int width,
                       int height,
                       int y_pitch,
                       int uv_pitch,
                       int rgb_pitch,
                       YUVType yuv_type) {
  unsigned int y_shift = yuv_type;
  for (int y = 0; y < height; ++y) {
    uint8* rgb_row = rgb_buf + y * rgb_pitch;
    const uint8* y_ptr = y_buf + y * y_pitch;
    const uint8* u_ptr = u_buf + (y >> y_shift) * uv_pitch;
    const uint8* v_ptr = v_buf + (y >> y_shift) * uv_pitch;

    FastConvertYUVToRGB32Row(y_ptr,
                             u_ptr,
                             v_ptr,
                             rgb_row,
                             width);
  }

  // MMX used for FastConvertYUVToRGB32Row requires emms instruction.
  EMMS();
}

#if USE_MMX
#if USE_SSE
// FilterRows combines two rows of the image using linear interpolation.
// SSE2 version blends 8 pixels at a time.
static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr,
                       int width, int scaled_y_fraction) {
  __m128i zero = _mm_setzero_si128();
  __m128i y1_fraction = _mm_set1_epi16(
      static_cast<uint16>(scaled_y_fraction >> 8));
  __m128i y0_fraction = _mm_set1_epi16(
      static_cast<uint16>((scaled_y_fraction >> 8) ^ 255));

  uint8* end = ybuf + width;
  if (ybuf < end) {
    do {
      __m128i y0 = _mm_loadl_epi64(reinterpret_cast<__m128i const*>(y0_ptr));
      __m128i y1 = _mm_loadl_epi64(reinterpret_cast<__m128i const*>(y1_ptr));
      y0 = _mm_unpacklo_epi8(y0, zero);
      y1 = _mm_unpacklo_epi8(y1, zero);
      y0 = _mm_mullo_epi16(y0, y0_fraction);
      y1 = _mm_mullo_epi16(y1, y1_fraction);
      y0 = _mm_add_epi16(y0, y1);  // 8.8 fixed point result
      y0 = _mm_srli_epi16(y0, 8);
      y0 = _mm_packus_epi16(y0, y0);
      _mm_storel_epi64(reinterpret_cast<__m128i *>(ybuf), y0);
      y0_ptr += 8;
      y1_ptr += 8;
      ybuf += 8;
    } while (ybuf < end);
  }
}

#else
// MMX version blends 4 pixels at a time.
static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr,
                       int width, int scaled_y_fraction) {
  __m64 zero = _mm_setzero_si64();
  __m64 y1_fraction = _mm_set1_pi16(
      static_cast<int16>(scaled_y_fraction >> 8));
  __m64 y0_fraction = _mm_set1_pi16(
      static_cast<int16>((scaled_y_fraction >> 8) ^ 255));

  uint8* end = ybuf + width;
  if (ybuf < end) {
    do {
      __m64 y0 = _mm_cvtsi32_si64(*reinterpret_cast<const int *>(y0_ptr));
      __m64 y1 = _mm_cvtsi32_si64(*reinterpret_cast<const int *>(y1_ptr));
      y0 = _mm_unpacklo_pi8(y0, zero);
      y1 = _mm_unpacklo_pi8(y1, zero);
      y0 = _mm_mullo_pi16(y0, y0_fraction);
      y1 = _mm_mullo_pi16(y1, y1_fraction);
      y0 = _mm_add_pi16(y0, y1);  // 8.8 fixed point result
      y0 = _mm_srli_pi16(y0, 8);
      y0 = _mm_packs_pu16(y0, y0);
      *reinterpret_cast<int *>(ybuf) = _mm_cvtsi64_si32(y0);
      y0_ptr += 4;
      y1_ptr += 4;
      ybuf += 4;
    } while (ybuf < end);
  }
}

#endif  // USE_SSE
#else  // no MMX or SSE
// C version blends 4 pixels at a time.
static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr,
                       int width, int scaled_y_fraction) {
  int y0_fraction = kFractionMax - scaled_y_fraction;
  int y1_fraction = scaled_y_fraction;
  uint8* end = ybuf + width;
  if (ybuf < end) {
    do {
      ybuf[0] = (y0_ptr[0] * (y0_fraction) + y1_ptr[0] * (y1_fraction)) >> 16;
      ybuf[1] = (y0_ptr[1] * (y0_fraction) + y1_ptr[1] * (y1_fraction)) >> 16;
      ybuf[2] = (y0_ptr[2] * (y0_fraction) + y1_ptr[2] * (y1_fraction)) >> 16;
      ybuf[3] = (y0_ptr[3] * (y0_fraction) + y1_ptr[3] * (y1_fraction)) >> 16;
      y0_ptr += 4;
      y1_ptr += 4;
      ybuf += 4;
    } while (ybuf < end);
  }
}
#endif  // USE_MMX

// Scale a frame of YUV to 32 bit ARGB.
void ScaleYUVToRGB32(const uint8* y_buf,
                     const uint8* u_buf,
                     const uint8* v_buf,
                     uint8* rgb_buf,
                     int width,
                     int height,
                     int scaled_width,
                     int scaled_height,
                     int y_pitch,
                     int uv_pitch,
                     int rgb_pitch,
                     YUVType yuv_type,
                     Rotate view_rotate,
                     ScaleFilter filter) {
  const int kFilterBufferSize = 8192;
  // Disable filtering if the screen is too big (to avoid buffer overflows).
  // This should never happen to regular users: they don't have monitors
  // wider than 8192 pixels.
  if (width > kFilterBufferSize)
    filter = FILTER_NONE;

  unsigned int y_shift = yuv_type;
  // Diagram showing origin and direction of source sampling.
  // ->0   4<-
  // 7       3
  //
  // 6       5
  // ->1   2<-
  // Rotations that start at right side of image.
  if ((view_rotate == ROTATE_180) ||
      (view_rotate == ROTATE_270) ||
      (view_rotate == MIRROR_ROTATE_0) ||
      (view_rotate == MIRROR_ROTATE_90)) {
    y_buf += width - 1;
    u_buf += width / 2 - 1;
    v_buf += width / 2 - 1;
    width = -width;
  }
  // Rotations that start at bottom of image.
  if ((view_rotate == ROTATE_90) ||
      (view_rotate == ROTATE_180) ||
      (view_rotate == MIRROR_ROTATE_90) ||
      (view_rotate == MIRROR_ROTATE_180)) {
    y_buf += (height - 1) * y_pitch;
    u_buf += ((height >> y_shift) - 1) * uv_pitch;
    v_buf += ((height >> y_shift) - 1) * uv_pitch;
    height = -height;
  }

  // Handle zero sized destination.
  if (scaled_width == 0 || scaled_height == 0)
    return;
  int scaled_dx = width * kFractionMax / scaled_width;
  int scaled_dy = height * kFractionMax / scaled_height;
  int scaled_dx_uv = scaled_dx;

  if ((view_rotate == ROTATE_90) ||
      (view_rotate == ROTATE_270)) {
    int tmp = scaled_height;
    scaled_height = scaled_width;
    scaled_width = tmp;
    tmp = height;
    height = width;
    width = tmp;
    int original_dx = scaled_dx;
    int original_dy = scaled_dy;
    scaled_dx = ((original_dy >> kFractionBits) * y_pitch) << kFractionBits;
    scaled_dx_uv = ((original_dy >> kFractionBits) * uv_pitch) << kFractionBits;
    scaled_dy = original_dx;
    if (view_rotate == ROTATE_90) {
      y_pitch = -1;
      uv_pitch = -1;
      height = -height;
    } else {
      y_pitch = 1;
      uv_pitch = 1;
    }
  }

  // Need padding because FilterRows() may write up to 15 extra pixels
  // after the end for SSE2 version.
  uint8 ybuf[kFilterBufferSize + 16];
  uint8 ubuf[kFilterBufferSize / 2 + 16];
  uint8 vbuf[kFilterBufferSize / 2 + 16];
  int yscale_fixed = (height << kFractionBits) / scaled_height;
  for (int y = 0; y < scaled_height; ++y) {
    uint8* dest_pixel = rgb_buf + y * rgb_pitch;
    int source_y_subpixel = (y * yscale_fixed);
    int source_y = source_y_subpixel >> kFractionBits;

    const uint8* y0_ptr = y_buf + source_y * y_pitch;
    const uint8* y1_ptr = y0_ptr + y_pitch;

    const uint8* u0_ptr = u_buf + (source_y >> y_shift) * uv_pitch;
    const uint8* u1_ptr = u0_ptr + uv_pitch;
    const uint8* v0_ptr = v_buf + (source_y >> y_shift) * uv_pitch;
    const uint8* v1_ptr = v0_ptr + uv_pitch;

    int scaled_y_fraction = source_y_subpixel & (kFractionMax - 1);
    int scaled_uv_fraction = (source_y_subpixel >> y_shift) & (kFractionMax - 1);

    const uint8* y_ptr = y0_ptr;
    const uint8* u_ptr = u0_ptr;
    const uint8* v_ptr = v0_ptr;
    // Apply vertical filtering if necessary.
    // TODO(fbarchard): Remove memcpy when not necessary.
    if (filter == media::FILTER_BILINEAR) {
      if (yscale_fixed != kFractionMax &&
          scaled_y_fraction && ((source_y + 1) < height)) {
        FilterRows(ybuf, y0_ptr, y1_ptr, width, scaled_y_fraction);
      } else {
        memcpy(ybuf, y0_ptr, width);
      }
      y_ptr = ybuf;
      ybuf[width] = ybuf[width-1];
      int uv_width = (width + 1) / 2;
      if (yscale_fixed != kFractionMax &&
          scaled_uv_fraction &&
          (((source_y >> y_shift) + 1) < (height >> y_shift))) {
        FilterRows(ubuf, u0_ptr, u1_ptr, uv_width, scaled_uv_fraction);
        FilterRows(vbuf, v0_ptr, v1_ptr, uv_width, scaled_uv_fraction);
      } else {
        memcpy(ubuf, u0_ptr, uv_width);
        memcpy(vbuf, v0_ptr, uv_width);
      }
      u_ptr = ubuf;
      v_ptr = vbuf;
      ubuf[uv_width] = ubuf[uv_width - 1];
      vbuf[uv_width] = vbuf[uv_width - 1];
    }
    if (scaled_dx == kFractionMax) {  // Not scaled
      FastConvertYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
                               dest_pixel, scaled_width);
    } else {
      if (filter == FILTER_BILINEAR)
        LinearScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
                                 dest_pixel, scaled_width, scaled_dx);
      else
        ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
                           dest_pixel, scaled_width, scaled_dx);
    }
  }

  // MMX used for FastConvertYUVToRGB32Row requires emms instruction.
  EMMS();
}

}  // namespace media
<commit_msg>fixed compilation problem with disabled SSE BUG=19113 TEST=none<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This webpage shows layout of YV12 and other YUV formats
// http://www.fourcc.org/yuv.php
// The actual conversion is best described here
// http://en.wikipedia.org/wiki/YUV
// An article on optimizing YUV conversion using tables instead of multiplies
// http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
//
// YV12 is a full plane of Y and a half height, half width chroma planes
// YV16 is a full plane of Y and a full height, half width chroma planes
//
// ARGB pixel format is output, which on little endian is stored as BGRA.
// The alpha is set to 255, allowing the application to use RGBA or RGB32.

#include "media/base/yuv_convert.h"

// Header for low level row functions.
#include "media/base/yuv_row.h"

#if USE_MMX
#if defined(_MSC_VER)
#include <intrin.h>
#else
#include <mmintrin.h>
#endif
#endif

#if USE_SSE
#include <emmintrin.h>
#endif

namespace media {

// 16.16 fixed point arithmetic.
const int kFractionBits = 16;
const int kFractionMax = 1 << kFractionBits;

// Convert a frame of YUV to 32 bit ARGB.
void ConvertYUVToRGB32(const uint8* y_buf,
                       const uint8* u_buf,
                       const uint8* v_buf,
                       uint8* rgb_buf,
                       int width,
                       int height,
                       int y_pitch,
                       int uv_pitch,
                       int rgb_pitch,
                       YUVType yuv_type) {
  unsigned int y_shift = yuv_type;
  for (int y = 0; y < height; ++y) {
    uint8* rgb_row = rgb_buf + y * rgb_pitch;
    const uint8* y_ptr = y_buf + y * y_pitch;
    const uint8* u_ptr = u_buf + (y >> y_shift) * uv_pitch;
    const uint8* v_ptr = v_buf + (y >> y_shift) * uv_pitch;

    FastConvertYUVToRGB32Row(y_ptr,
                             u_ptr,
                             v_ptr,
                             rgb_row,
                             width);
  }

  // MMX used for FastConvertYUVToRGB32Row requires emms instruction.
  EMMS();
}

#if USE_MMX
#if USE_SSE
// FilterRows combines two rows of the image using linear interpolation.
// SSE2 version blends 8 pixels at a time.
static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr,
                       int width, int scaled_y_fraction) {
  __m128i zero = _mm_setzero_si128();
  __m128i y1_fraction = _mm_set1_epi16(
      static_cast<uint16>(scaled_y_fraction >> 8));
  __m128i y0_fraction = _mm_set1_epi16(
      static_cast<uint16>((scaled_y_fraction >> 8) ^ 255));

  uint8* end = ybuf + width;
  if (ybuf < end) {
    do {
      __m128i y0 = _mm_loadl_epi64(reinterpret_cast<__m128i const*>(y0_ptr));
      __m128i y1 = _mm_loadl_epi64(reinterpret_cast<__m128i const*>(y1_ptr));
      y0 = _mm_unpacklo_epi8(y0, zero);
      y1 = _mm_unpacklo_epi8(y1, zero);
      y0 = _mm_mullo_epi16(y0, y0_fraction);
      y1 = _mm_mullo_epi16(y1, y1_fraction);
      y0 = _mm_add_epi16(y0, y1);  // 8.8 fixed point result
      y0 = _mm_srli_epi16(y0, 8);
      y0 = _mm_packus_epi16(y0, y0);
      _mm_storel_epi64(reinterpret_cast<__m128i *>(ybuf), y0);
      y0_ptr += 8;
      y1_ptr += 8;
      ybuf += 8;
    } while (ybuf < end);
  }
}

#else
// MMX version blends 4 pixels at a time.
static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr,
                       int width, int scaled_y_fraction) {
  __m64 zero = _mm_setzero_si64();
  __m64 y1_fraction = _mm_set1_pi16(
      static_cast<int16>(scaled_y_fraction >> 8));
  __m64 y0_fraction = _mm_set1_pi16(
      static_cast<int16>((scaled_y_fraction >> 8) ^ 255));

  uint8* end = ybuf + width;
  if (ybuf < end) {
    do {
      __m64 y0 = _mm_cvtsi32_si64(*reinterpret_cast<const int *>(y0_ptr));
      __m64 y1 = _mm_cvtsi32_si64(*reinterpret_cast<const int *>(y1_ptr));
      y0 = _mm_unpacklo_pi8(y0, zero);
      y1 = _mm_unpacklo_pi8(y1, zero);
      y0 = _mm_mullo_pi16(y0, y0_fraction);
      y1 = _mm_mullo_pi16(y1, y1_fraction);
      y0 = _mm_add_pi16(y0, y1);  // 8.8 fixed point result
      y0 = _mm_srli_pi16(y0, 8);
      y0 = _mm_packs_pu16(y0, y0);
      *reinterpret_cast<int *>(ybuf) = _mm_cvtsi64_si32(y0);
      y0_ptr += 4;
      y1_ptr += 4;
      ybuf += 4;
    } while (ybuf < end);
  }
}

#endif  // USE_SSE
#else  // no MMX or SSE
// C version blends 4 pixels at a time.
static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr,
                       int width, int scaled_y_fraction) {
  int y0_fraction = kFractionMax - scaled_y_fraction;
  int y1_fraction = scaled_y_fraction;
  uint8* end = ybuf + width;
  if (ybuf < end) {
    do {
      ybuf[0] = (y0_ptr[0] * (y0_fraction) + y1_ptr[0] * (y1_fraction)) >> 16;
      ybuf[1] = (y0_ptr[1] * (y0_fraction) + y1_ptr[1] * (y1_fraction)) >> 16;
      ybuf[2] = (y0_ptr[2] * (y0_fraction) + y1_ptr[2] * (y1_fraction)) >> 16;
      ybuf[3] = (y0_ptr[3] * (y0_fraction) + y1_ptr[3] * (y1_fraction)) >> 16;
      y0_ptr += 4;
      y1_ptr += 4;
      ybuf += 4;
    } while (ybuf < end);
  }
}
#endif  // USE_MMX

// Scale a frame of YUV to 32 bit ARGB.
void ScaleYUVToRGB32(const uint8* y_buf,
                     const uint8* u_buf,
                     const uint8* v_buf,
                     uint8* rgb_buf,
                     int width,
                     int height,
                     int scaled_width,
                     int scaled_height,
                     int y_pitch,
                     int uv_pitch,
                     int rgb_pitch,
                     YUVType yuv_type,
                     Rotate view_rotate,
                     ScaleFilter filter) {
  const int kFilterBufferSize = 8192;
  // Disable filtering if the screen is too big (to avoid buffer overflows).
  // This should never happen to regular users: they don't have monitors
  // wider than 8192 pixels.
  if (width > kFilterBufferSize)
    filter = FILTER_NONE;

  unsigned int y_shift = yuv_type;
  // Diagram showing origin and direction of source sampling.
  // ->0   4<-
  // 7       3
  //
  // 6       5
  // ->1   2<-
  // Rotations that start at right side of image.
  if ((view_rotate == ROTATE_180) ||
      (view_rotate == ROTATE_270) ||
      (view_rotate == MIRROR_ROTATE_0) ||
      (view_rotate == MIRROR_ROTATE_90)) {
    y_buf += width - 1;
    u_buf += width / 2 - 1;
    v_buf += width / 2 - 1;
    width = -width;
  }
  // Rotations that start at bottom of image.
  if ((view_rotate == ROTATE_90) ||
      (view_rotate == ROTATE_180) ||
      (view_rotate == MIRROR_ROTATE_90) ||
      (view_rotate == MIRROR_ROTATE_180)) {
    y_buf += (height - 1) * y_pitch;
    u_buf += ((height >> y_shift) - 1) * uv_pitch;
    v_buf += ((height >> y_shift) - 1) * uv_pitch;
    height = -height;
  }

  // Handle zero sized destination.
  if (scaled_width == 0 || scaled_height == 0)
    return;
  int scaled_dx = width * kFractionMax / scaled_width;
  int scaled_dy = height * kFractionMax / scaled_height;
  int scaled_dx_uv = scaled_dx;

  if ((view_rotate == ROTATE_90) ||
      (view_rotate == ROTATE_270)) {
    int tmp = scaled_height;
    scaled_height = scaled_width;
    scaled_width = tmp;
    tmp = height;
    height = width;
    width = tmp;
    int original_dx = scaled_dx;
    int original_dy = scaled_dy;
    scaled_dx = ((original_dy >> kFractionBits) * y_pitch) << kFractionBits;
    scaled_dx_uv = ((original_dy >> kFractionBits) * uv_pitch) << kFractionBits;
    scaled_dy = original_dx;
    if (view_rotate == ROTATE_90) {
      y_pitch = -1;
      uv_pitch = -1;
      height = -height;
    } else {
      y_pitch = 1;
      uv_pitch = 1;
    }
  }

  // Need padding because FilterRows() may write up to 15 extra pixels
  // after the end for SSE2 version.
  uint8 ybuf[kFilterBufferSize + 16];
  uint8 ubuf[kFilterBufferSize / 2 + 16];
  uint8 vbuf[kFilterBufferSize / 2 + 16];
  int yscale_fixed = (height << kFractionBits) / scaled_height;
  for (int y = 0; y < scaled_height; ++y) {
    uint8* dest_pixel = rgb_buf + y * rgb_pitch;
    int source_y_subpixel = (y * yscale_fixed);
    int source_y = source_y_subpixel >> kFractionBits;

    const uint8* y0_ptr = y_buf + source_y * y_pitch;
    const uint8* y1_ptr = y0_ptr + y_pitch;

    const uint8* u0_ptr = u_buf + (source_y >> y_shift) * uv_pitch;
    const uint8* u1_ptr = u0_ptr + uv_pitch;
    const uint8* v0_ptr = v_buf + (source_y >> y_shift) * uv_pitch;
    const uint8* v1_ptr = v0_ptr + uv_pitch;

    int scaled_y_fraction = source_y_subpixel & (kFractionMax - 1);
    int scaled_uv_fraction = (source_y_subpixel >> y_shift) & (kFractionMax - 1);

    const uint8* y_ptr = y0_ptr;
    const uint8* u_ptr = u0_ptr;
    const uint8* v_ptr = v0_ptr;
    // Apply vertical filtering if necessary.
    // TODO(fbarchard): Remove memcpy when not necessary.
    if (filter == media::FILTER_BILINEAR) {
      if (yscale_fixed != kFractionMax &&
          scaled_y_fraction && ((source_y + 1) < height)) {
        FilterRows(ybuf, y0_ptr, y1_ptr, width, scaled_y_fraction);
      } else {
        memcpy(ybuf, y0_ptr, width);
      }
      y_ptr = ybuf;
      ybuf[width] = ybuf[width-1];
      int uv_width = (width + 1) / 2;
      if (yscale_fixed != kFractionMax &&
          scaled_uv_fraction &&
          (((source_y >> y_shift) + 1) < (height >> y_shift))) {
        FilterRows(ubuf, u0_ptr, u1_ptr, uv_width, scaled_uv_fraction);
        FilterRows(vbuf, v0_ptr, v1_ptr, uv_width, scaled_uv_fraction);
      } else {
        memcpy(ubuf, u0_ptr, uv_width);
        memcpy(vbuf, v0_ptr, uv_width);
      }
      u_ptr = ubuf;
      v_ptr = vbuf;
      ubuf[uv_width] = ubuf[uv_width - 1];
      vbuf[uv_width] = vbuf[uv_width - 1];
    }
    if (scaled_dx == kFractionMax) {  // Not scaled
      FastConvertYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
                               dest_pixel, scaled_width);
    } else {
      if (filter == FILTER_BILINEAR)
        LinearScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
                                 dest_pixel, scaled_width, scaled_dx);
      else
        ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
                           dest_pixel, scaled_width, scaled_dx);
    }
  }

  // MMX used for FastConvertYUVToRGB32Row requires emms instruction.
  EMMS();
}

}  // namespace media
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) version 3, or any
 * later version accepted by the membership of KDE e.V. (or its
 * successor approved by the membership of KDE e.V.), which shall
 * act as a proxy defined in Section 6 of version 3 of the license.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "PreviewImageProvider.h"

#include <kiconloader.h>
#include <kio/previewjob.h>

#include <QCoreApplication>
#include <QDir>
#include <QIcon>
#include <QMimeDatabase>
#include <QThreadPool>
#include <QDebug>

class PreviewImageProvider::Private
{
public:
    Private() {};
    QThreadPool pool;
};

PreviewImageProvider::PreviewImageProvider()
    : QQuickAsyncImageProvider()
    , d(new Private)
{
    qRegisterMetaType<KFileItem>("KFileItem");
}

PreviewImageProvider::~PreviewImageProvider()
{
    delete d;
}

class PreviewResponse : public QQuickImageResponse
{
    public:
        PreviewResponse(const QString &id, const QSize &requestedSize, QThreadPool *pool)
        {
            m_runnable = new PreviewRunnable(id, requestedSize);
            connect(m_runnable, &PreviewRunnable::done, this, &PreviewResponse::handleDone);
            pool->start(m_runnable);
        }

        void handleDone(QImage image) {
            m_image = image;
            emit finished();
        }

        QQuickTextureFactory *textureFactory() const override
        {
            return QQuickTextureFactory::textureFactoryForImage(m_image);
        }

        void cancel() override
        {
            m_runnable->abort();
        }

        PreviewRunnable* m_runnable{nullptr};
        QImage m_image;
};

QQuickImageResponse * PreviewImageProvider::requestImageResponse(const QString& id, const QSize& requestedSize)
{
    PreviewResponse* response = new PreviewResponse(id, requestedSize, &d->pool);
    return response;
}

class PreviewRunnable::Private {
public:
    Private() {}
    QString id;
    QSize requestedSize;

    QImage preview;
    bool jobCompletion{false};
    KIO::PreviewJob* job{nullptr};
};

PreviewRunnable::PreviewRunnable(const QString& id, const QSize& requestedSize)
    : d(new Private)
{
    d->id = id;
    d->requestedSize = requestedSize;
}

void PreviewRunnable::run()
{
    QImage image;

    QSize ourSize(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous);
    if(d->requestedSize.width() > 0 && d->requestedSize.height() > 0)
    {
        ourSize = d->requestedSize;
    }

    if(QFile(d->id).exists())
    {
        QMimeDatabase db;
        QList<QMimeType> mimetypes = db.mimeTypesForFileName(d->id);
        QString mimetype;
        if(mimetypes.count() > 0)
        {
            mimetype = mimetypes.first().name();
        }

        static QStringList allPlugins{KIO::PreviewJob::availablePlugins()};
        d->job = new KIO::PreviewJob(KFileItemList() << KFileItem(QUrl::fromLocalFile(d->id), mimetype, 0), ourSize, &allPlugins);
        d->job->setIgnoreMaximumSize(true);
        d->job->setScaleType(KIO::PreviewJob::ScaledAndCached);
        connect(d->job, SIGNAL(gotPreview(KFileItem,QPixmap)), SLOT(updatePreview(KFileItem,QPixmap)));
        connect(d->job, SIGNAL(failed(KFileItem)), SLOT(fallbackPreview(KFileItem)));
        connect(d->job, SIGNAL(finished(KJob*)), SLOT(finishedPreview(KJob*)));

        d->jobCompletion = false;
        if(d->job->exec())
        {
            // Do not access the job after this point! As we are requesting that
            // it be deleted in finishedPreview(), don't expect it to be around.
            while(!d->jobCompletion) {
                // Let's let the job do its thing and whatnot...
                qApp->processEvents();
            }
            if(!d->preview.isNull())
            {
                if(d->requestedSize.width() > 0 && d->requestedSize.height() > 0)
                {
                    image = d->preview.scaled(d->requestedSize);
                }
                else
                {
                    image = d->preview;
                }
            }
        }
    }
    else
    {
        image = QImage(ourSize, QImage::Format_ARGB32);
    }

    Q_EMIT done(image);
}

void PreviewRunnable::abort()
{
    d->job->kill();
}

void PreviewRunnable::fallbackPreview(const KFileItem& item)
{
    KIO::PreviewJob* previewJob = qobject_cast<KIO::PreviewJob*>(sender());
    if(previewJob)
    {
        QMimeDatabase db;
        QImage preview = QIcon::fromTheme(db.mimeTypeForName(item.mimetype()).iconName()).pixmap(d->requestedSize).toImage();
        d->preview = preview;
        d->jobCompletion = true;
    }
}

void PreviewRunnable::updatePreview(const KFileItem&, const QPixmap& p)
{
    KIO::PreviewJob* previewJob = qobject_cast<KIO::PreviewJob*>(sender());
    if(previewJob)
    {
        d->preview = p.toImage();
    }
}

void PreviewRunnable::finishedPreview(KJob* /*job*/)
{
    d->jobCompletion = true;
}
<commit_msg>Don't try and abort a null job, we might do a splode...<commit_after>/*
 * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) version 3, or any
 * later version accepted by the membership of KDE e.V. (or its
 * successor approved by the membership of KDE e.V.), which shall
 * act as a proxy defined in Section 6 of version 3 of the license.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "PreviewImageProvider.h"

#include <kiconloader.h>
#include <kio/previewjob.h>

#include <QCoreApplication>
#include <QDir>
#include <QIcon>
#include <QMimeDatabase>
#include <QThreadPool>
#include <QDebug>

class PreviewImageProvider::Private
{
public:
    Private() {};
    QThreadPool pool;
};

PreviewImageProvider::PreviewImageProvider()
    : QQuickAsyncImageProvider()
    , d(new Private)
{
    qRegisterMetaType<KFileItem>("KFileItem");
}

PreviewImageProvider::~PreviewImageProvider()
{
    delete d;
}

class PreviewResponse : public QQuickImageResponse
{
    public:
        PreviewResponse(const QString &id, const QSize &requestedSize, QThreadPool *pool)
        {
            m_runnable = new PreviewRunnable(id, requestedSize);
            connect(m_runnable, &PreviewRunnable::done, this, &PreviewResponse::handleDone);
            pool->start(m_runnable);
        }

        void handleDone(QImage image) {
            m_image = image;
            emit finished();
        }

        QQuickTextureFactory *textureFactory() const override
        {
            return QQuickTextureFactory::textureFactoryForImage(m_image);
        }

        void cancel() override
        {
            m_runnable->abort();
        }

        PreviewRunnable* m_runnable{nullptr};
        QImage m_image;
};

QQuickImageResponse * PreviewImageProvider::requestImageResponse(const QString& id, const QSize& requestedSize)
{
    PreviewResponse* response = new PreviewResponse(id, requestedSize, &d->pool);
    return response;
}

class PreviewRunnable::Private {
public:
    Private() {}
    QString id;
    QSize requestedSize;

    bool abort{false};

    QImage preview;
    bool jobCompletion{false};
    KIO::PreviewJob* job{nullptr};
};

PreviewRunnable::PreviewRunnable(const QString& id, const QSize& requestedSize)
    : d(new Private)
{
    d->id = id;
    d->requestedSize = requestedSize;
}

void PreviewRunnable::run()
{
    QImage image;

    QSize ourSize(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous);
    if(d->requestedSize.width() > 0 && d->requestedSize.height() > 0)
    {
        ourSize = d->requestedSize;
    }

    if(QFile(d->id).exists())
    {
        QMimeDatabase db;
        QList<QMimeType> mimetypes = db.mimeTypesForFileName(d->id);
        QString mimetype;
        if(mimetypes.count() > 0)
        {
            mimetype = mimetypes.first().name();
        }

        if(!d->abort) {
            static QStringList allPlugins{KIO::PreviewJob::availablePlugins()};
            d->job = new KIO::PreviewJob(KFileItemList() << KFileItem(QUrl::fromLocalFile(d->id), mimetype, 0), ourSize, &allPlugins);
            d->job->setIgnoreMaximumSize(true);
            d->job->setScaleType(KIO::PreviewJob::ScaledAndCached);
            connect(d->job, SIGNAL(gotPreview(KFileItem,QPixmap)), SLOT(updatePreview(KFileItem,QPixmap)));
            connect(d->job, SIGNAL(failed(KFileItem)), SLOT(fallbackPreview(KFileItem)));
            connect(d->job, SIGNAL(finished(KJob*)), SLOT(finishedPreview(KJob*)));

            d->jobCompletion = false;
            if(d->job->exec())
            {
                // Do not access the job after this point! As we are requesting that
                // it be deleted in finishedPreview(), don't expect it to be around.
                while(!d->jobCompletion) {
                    // Let's let the job do its thing and whatnot...
                    qApp->processEvents();
                }
                if(!d->preview.isNull())
                {
                    if(d->requestedSize.width() > 0 && d->requestedSize.height() > 0)
                    {
                        image = d->preview.scaled(d->requestedSize);
                    }
                    else
                    {
                        image = d->preview;
                    }
                }
            }
        }
    }
    else
    {
        image = QImage(ourSize, QImage::Format_ARGB32);
    }

    Q_EMIT done(image);
}

void PreviewRunnable::abort()
{
    if (d->job) {
        d->abort = true;
        d->job->kill();
    }
}

void PreviewRunnable::fallbackPreview(const KFileItem& item)
{
    KIO::PreviewJob* previewJob = qobject_cast<KIO::PreviewJob*>(sender());
    if(previewJob)
    {
        QMimeDatabase db;
        QImage preview = QIcon::fromTheme(db.mimeTypeForName(item.mimetype()).iconName()).pixmap(d->requestedSize).toImage();
        d->preview = preview;
        d->jobCompletion = true;
    }
}

void PreviewRunnable::updatePreview(const KFileItem&, const QPixmap& p)
{
    KIO::PreviewJob* previewJob = qobject_cast<KIO::PreviewJob*>(sender());
    if(previewJob)
    {
        d->preview = p.toImage();
    }
}

void PreviewRunnable::finishedPreview(KJob* /*job*/)
{
    d->jobCompletion = true;
}
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

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

#include "QmitkDataTreeFilterDemo.h"
#include "QmitkDataTreeFilterDemoControls.h"
#include "QmitkPropertyViewFactory.h"
#include "QmitkDataTreeComboBox.h"
#include "QmitkDataTreeListView.h"
#include "QmitkStdMultiWidget.h"

#include "icon.xpm"

#include "mitkDataTreeFilterFunctions.h"
#include "mitkSurface.h"

  QmitkDataTreeFilterDemo::QmitkDataTreeFilterDemo(QObject *parent, const char *name, QmitkStdMultiWidget *mitkStdMultiWidget, mitk::DataTreeIteratorBase* it)
: QmitkFunctionality(parent, name, it),
  m_MultiWidget(mitkStdMultiWidget),
  m_Controls(NULL),
  m_FilterInitialized(false)
{
  SetAvailability(true);
}

QmitkDataTreeFilterDemo::~QmitkDataTreeFilterDemo()
{
  if(m_DataTreeFilter.IsNotNull())
    m_DataTreeFilter->RemoveObserver( m_ListboxModifiedConnection );
}

QWidget* QmitkDataTreeFilterDemo::CreateMainWidget(QWidget* /*parent*/)
{
  return NULL;
}

QWidget* QmitkDataTreeFilterDemo::CreateControlWidget(QWidget* parent)
{
  if (!m_Controls)
  {
    m_Controls = new QmitkDataTreeFilterDemoControls(parent);
  }
  return m_Controls;
}

void QmitkDataTreeFilterDemo::CreateConnections()
{
  if ( m_Controls )
  {
    connect( m_Controls->TreeComboBox, SIGNAL(activated(const mitk::DataTreeFilter::Item*)),
                                 this, SLOT(onComboBoxItemSelected(const mitk::DataTreeFilter::Item*)) );

    connect( m_Controls->TreeListBox, SIGNAL(clicked(const mitk::DataTreeFilter::Item*, bool)),
                                this, SLOT(onListboxItemClicked(const mitk::DataTreeFilter::Item*, bool)) );

    connect( m_Controls->TreeListBox, SIGNAL(newItem(const mitk::DataTreeFilter::Item*)),
                                this, SLOT(onListboxItemAdded(const mitk::DataTreeFilter::Item*)) );

    connect( m_Controls->cmbFilterFunction, SIGNAL(activated(int)),
                                      this, SLOT(onCmbFilterFunctionActivated(int)) );

    connect( (QObject*)(m_Controls->chkHierarchy), SIGNAL(toggled(bool)),
                                 this, SLOT(onChkHierarchyToggled(bool)) );
    }
}

QAction* QmitkDataTreeFilterDemo::CreateAction(QActionGroup* parent)
{
  QAction* action;
    action = new QAction( tr( "Demo for mitk::DataTreeFilter" ), QPixmap((const char**)icon_xpm), tr( "DataTreeFilterDemo" ), 0, parent, "DataTreeFilterDemo" );
  return action;
}

void QmitkDataTreeFilterDemo::TreeChanged()
{
  m_Controls->TreeComboBox->Update(); // recreate contents. To update it all of the time, even when the functionality is deactivated,
                                     //  call m_Controls->TreeComboBox->SetAutoUpdate(true) at some point
}

void QmitkDataTreeFilterDemo::Activated()
{
  QmitkFunctionality::Activated();

  if (!m_FilterInitialized)
  {
   // init the combobox (to show only images, which is also the default)
    m_Controls->TreeComboBox->SetDataTree( GetDataTreeIterator() );
    m_Controls->TreeComboBox->GetFilter()->SetFilter( mitk::IsBaseDataType<mitk::Image>() );  // this line could be skipped because this filter is the default at the moment

    // uncomment to get more output from the DataTreeFilter
    //m_Controls->TreeComboBox->GetFilter()->SetDebugOn();

    // define the list of segmentations
    m_DataTreeFilter = mitk::DataTreeFilter::New( GetDataTreeIterator()->GetTree() );
    m_DataTreeFilter->SetSelectionMode(mitk::DataTreeFilter::SINGLE_SELECT);
    m_DataTreeFilter->SetHierarchyHandling(mitk::DataTreeFilter::FLATTEN_HIERARCHY);
    m_DataTreeFilter->SetFilter( mitk::IsGoodDataTreeNode() ); // show everything with data

    // define what is displayed about the segmentations
    mitk::DataTreeFilter::PropertyList visible_props;
    visible_props.push_back("visible");
    visible_props.push_back("color");
    visible_props.push_back("name");
    m_DataTreeFilter->SetVisibleProperties(visible_props);

    mitk::DataTreeFilter::PropertyList editable_props;
    editable_props.push_back("visible");
    editable_props.push_back("name");
    editable_props.push_back("color");
    m_DataTreeFilter->SetEditableProperties(editable_props);

    mitk::DataTreeFilter::PropertyList property_labels;
    property_labels.push_back(" ");
    property_labels.push_back(" ");
    property_labels.push_back("Name");
    m_DataTreeFilter->SetPropertiesLabels(property_labels);

    m_Controls->TreeListBox->SetViewType("name", QmitkPropertyViewFactory::etON_DEMAND_EDIT);
    m_Controls->TreeListBox->SetFilter( m_DataTreeFilter );

    // uncomment to get more output from the DataTreeFilter
    //m_DataTreeFilter->SetDebugOn();

    ConnectListboxNotification();

    m_FilterInitialized = true;
  }
}

void QmitkDataTreeFilterDemo::Deactivated()
{
  QmitkFunctionality::Deactivated();
}

void QmitkDataTreeFilterDemo::ConnectListboxNotification()
{
  itk::ReceptorMemberCommand<QmitkDataTreeFilterDemo>::Pointer command = itk::ReceptorMemberCommand<QmitkDataTreeFilterDemo>::New();
  command->SetCallbackFunction(this, &QmitkDataTreeFilterDemo::ListboxModifiedHandler);
  m_ListboxModifiedConnection = m_DataTreeFilter->AddObserver(itk::ModifiedEvent(), command);
}

void QmitkDataTreeFilterDemo::onComboBoxItemSelected(const mitk::DataTreeFilter::Item* item)
{
    std::cout << "(Combobox) Item " << item << " selected." << std::endl;
  if (item)
  {
    const mitk::DataTreeNode* node = item->GetNode();

    if (node && node->GetData())
    {
      // reinit multi-widget for the selected image
      m_MultiWidget->InitializeStandardViews( node->GetData()->GetTimeSlicedGeometry() );
      mitk::RenderingManager::GetInstance()->RequestUpdateAll();
    }
  }
}

void QmitkDataTreeFilterDemo::MoveCrossHairToItem(const mitk::DataTreeFilter::Item* item)
{
  if (!item) return;

  // get tree node
  const mitk::DataTreeNode* node( item->GetNode() );
  if (!node) return;

  // determine center of node
  mitk::Point2D p2d;
  if ( node->GetData() &&
       node->GetData()->GetGeometry() )
  {
    mitk::Point3D center( node->GetData()->GetGeometry()->GetCenter() );

    // tell the multiwidget to move there
    m_MultiWidget->MoveCrossToPosition( center );
  }
}

void QmitkDataTreeFilterDemo::onListboxItemClicked(const mitk::DataTreeFilter::Item* item, bool selected)
{
  if (selected)
    std::cout << "(Listbox) Item " << item << " selected." << std::endl;
  else
    std::cout << "(Listbox) Item " << item << " deselected." << std::endl;

  if (!selected) return;

  MoveCrossHairToItem(item);
}

void QmitkDataTreeFilterDemo::onListboxItemAdded(const mitk::DataTreeFilter::Item* item)
{
  if ( !IsActivated() ) return; // don't do anything if functionality isn't activated

  MoveCrossHairToItem(item);
}

void QmitkDataTreeFilterDemo::ListboxModifiedHandler( const itk::EventObject& /*e*/ )
{
  std::cout << "(Listbox) Something changed." << std::endl;

  //const mitk::DataTreeFilter::ItemList* items = m_DataTreeFilter->GetItems(); //in case you want to iterate over them
}

void QmitkDataTreeFilterDemo::onCmbFilterFunctionActivated(int i)
{
  switch (i)
  {
    case 0:
      m_DataTreeFilter->SetFilter( mitk::IsGoodDataTreeNode() );
      break;
    case 1:
      m_DataTreeFilter->SetFilter( mitk::IsBaseDataType<mitk::Image>() );
      break;
    case 2:
      m_DataTreeFilter->SetFilter( mitk::IsBaseDataType<mitk::Surface>() );
      break;
    case 3:
      m_DataTreeFilter->SetFilter( mitk::IsDataTreeNode() ); // probably not what the label promises
      break;
   }
}

void QmitkDataTreeFilterDemo::onChkHierarchyToggled(bool on)
{
  if (on)
    m_DataTreeFilter->SetHierarchyHandling( mitk::DataTreeFilter::PRESERVE_HIERARCHY );
  else
    m_DataTreeFilter->SetHierarchyHandling( mitk::DataTreeFilter::FLATTEN_HIERARCHY );
}
<commit_msg>CHG: removed debug output<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

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

#include "QmitkDataTreeFilterDemo.h"
#include "QmitkDataTreeFilterDemoControls.h"
#include "QmitkPropertyViewFactory.h"
#include "QmitkDataTreeComboBox.h"
#include "QmitkDataTreeListView.h"
#include "QmitkStdMultiWidget.h"

#include "icon.xpm"

#include "mitkDataTreeFilterFunctions.h"
#include "mitkSurface.h"

  QmitkDataTreeFilterDemo::QmitkDataTreeFilterDemo(QObject *parent, const char *name, QmitkStdMultiWidget *mitkStdMultiWidget, mitk::DataTreeIteratorBase* it)
: QmitkFunctionality(parent, name, it),
  m_MultiWidget(mitkStdMultiWidget),
  m_Controls(NULL),
  m_FilterInitialized(false)
{
  SetAvailability(true);
}

QmitkDataTreeFilterDemo::~QmitkDataTreeFilterDemo()
{
  if(m_DataTreeFilter.IsNotNull())
    m_DataTreeFilter->RemoveObserver( m_ListboxModifiedConnection );
}

QWidget* QmitkDataTreeFilterDemo::CreateMainWidget(QWidget* /*parent*/)
{
  return NULL;
}

QWidget* QmitkDataTreeFilterDemo::CreateControlWidget(QWidget* parent)
{
  if (!m_Controls)
  {
    m_Controls = new QmitkDataTreeFilterDemoControls(parent);
  }
  return m_Controls;
}

void QmitkDataTreeFilterDemo::CreateConnections()
{
  if ( m_Controls )
  {
    connect( m_Controls->TreeComboBox, SIGNAL(activated(const mitk::DataTreeFilter::Item*)),
                                 this, SLOT(onComboBoxItemSelected(const mitk::DataTreeFilter::Item*)) );

    connect( m_Controls->TreeListBox, SIGNAL(clicked(const mitk::DataTreeFilter::Item*, bool)),
                                this, SLOT(onListboxItemClicked(const mitk::DataTreeFilter::Item*, bool)) );

    connect( m_Controls->TreeListBox, SIGNAL(newItem(const mitk::DataTreeFilter::Item*)),
                                this, SLOT(onListboxItemAdded(const mitk::DataTreeFilter::Item*)) );

    connect( m_Controls->cmbFilterFunction, SIGNAL(activated(int)),
                                      this, SLOT(onCmbFilterFunctionActivated(int)) );

    connect( (QObject*)(m_Controls->chkHierarchy), SIGNAL(toggled(bool)),
                                 this, SLOT(onChkHierarchyToggled(bool)) );
    }
}

QAction* QmitkDataTreeFilterDemo::CreateAction(QActionGroup* parent)
{
  QAction* action;
    action = new QAction( tr( "Demo for mitk::DataTreeFilter" ), QPixmap((const char**)icon_xpm), tr( "DataTreeFilterDemo" ), 0, parent, "DataTreeFilterDemo" );
  return action;
}

void QmitkDataTreeFilterDemo::TreeChanged()
{
  m_Controls->TreeComboBox->Update(); // recreate contents. To update it all of the time, even when the functionality is deactivated,
                                     //  call m_Controls->TreeComboBox->SetAutoUpdate(true) at some point
}

void QmitkDataTreeFilterDemo::Activated()
{
  QmitkFunctionality::Activated();

  if (!m_FilterInitialized)
  {
   // init the combobox (to show only images, which is also the default)
    m_Controls->TreeComboBox->SetDataTree( GetDataTreeIterator() );
    m_Controls->TreeComboBox->GetFilter()->SetFilter( mitk::IsBaseDataType<mitk::Image>() );  // this line could be skipped because this filter is the default at the moment

    // uncomment to get more output from the DataTreeFilter
    //m_Controls->TreeComboBox->GetFilter()->SetDebugOn();

    // define the list of segmentations
    m_DataTreeFilter = mitk::DataTreeFilter::New( GetDataTreeIterator()->GetTree() );
    m_DataTreeFilter->SetSelectionMode(mitk::DataTreeFilter::SINGLE_SELECT);
    m_DataTreeFilter->SetHierarchyHandling(mitk::DataTreeFilter::FLATTEN_HIERARCHY);
    m_DataTreeFilter->SetFilter( mitk::IsGoodDataTreeNode() ); // show everything with data

    // define what is displayed about the segmentations
    mitk::DataTreeFilter::PropertyList visible_props;
    visible_props.push_back("visible");
    visible_props.push_back("color");
    visible_props.push_back("name");
    m_DataTreeFilter->SetVisibleProperties(visible_props);

    mitk::DataTreeFilter::PropertyList editable_props;
    editable_props.push_back("visible");
    editable_props.push_back("name");
    editable_props.push_back("color");
    m_DataTreeFilter->SetEditableProperties(editable_props);

    mitk::DataTreeFilter::PropertyList property_labels;
    property_labels.push_back(" ");
    property_labels.push_back(" ");
    property_labels.push_back("Name");
    m_DataTreeFilter->SetPropertiesLabels(property_labels);

    m_Controls->TreeListBox->SetViewType("name", QmitkPropertyViewFactory::etON_DEMAND_EDIT);
    m_Controls->TreeListBox->SetFilter( m_DataTreeFilter );

    // uncomment to get more output from the DataTreeFilter
    //m_DataTreeFilter->SetDebugOn();

    ConnectListboxNotification();

    m_FilterInitialized = true;
  }
}

void QmitkDataTreeFilterDemo::Deactivated()
{
  QmitkFunctionality::Deactivated();
}

void QmitkDataTreeFilterDemo::ConnectListboxNotification()
{
  itk::ReceptorMemberCommand<QmitkDataTreeFilterDemo>::Pointer command = itk::ReceptorMemberCommand<QmitkDataTreeFilterDemo>::New();
  command->SetCallbackFunction(this, &QmitkDataTreeFilterDemo::ListboxModifiedHandler);
  m_ListboxModifiedConnection = m_DataTreeFilter->AddObserver(itk::ModifiedEvent(), command);
}

void QmitkDataTreeFilterDemo::onComboBoxItemSelected(const mitk::DataTreeFilter::Item* item)
{
    std::cout << "(Combobox) Item " << item << " selected." << std::endl;
  if (item)
  {
    const mitk::DataTreeNode* node = item->GetNode();

    if (node && node->GetData())
    {
      // reinit multi-widget for the selected image
      m_MultiWidget->InitializeStandardViews( node->GetData()->GetTimeSlicedGeometry() );
      mitk::RenderingManager::GetInstance()->RequestUpdateAll();
    }
  }
}

void QmitkDataTreeFilterDemo::MoveCrossHairToItem(const mitk::DataTreeFilter::Item* item)
{
  if (!item) return;

  // get tree node
  const mitk::DataTreeNode* node( item->GetNode() );
  if (!node) return;

  // determine center of node
  mitk::Point2D p2d;
  if ( node->GetData() &&
       node->GetData()->GetGeometry() )
  {
    mitk::Point3D center( node->GetData()->GetGeometry()->GetCenter() );

    // tell the multiwidget to move there
    m_MultiWidget->MoveCrossToPosition( center );
  }
}

void QmitkDataTreeFilterDemo::onListboxItemClicked(const mitk::DataTreeFilter::Item* item, bool selected)
{
  if (selected)
    std::cout << "(Listbox) Item " << item << " selected." << std::endl;
  else
    std::cout << "(Listbox) Item " << item << " deselected." << std::endl;

  if (!selected) return;

  MoveCrossHairToItem(item);
}

void QmitkDataTreeFilterDemo::onListboxItemAdded(const mitk::DataTreeFilter::Item* item)
{
  if ( !IsActivated() ) return; // don't do anything if functionality isn't activated

  MoveCrossHairToItem(item);
}

void QmitkDataTreeFilterDemo::ListboxModifiedHandler( const itk::EventObject& /*e*/ )
{
  // std::cout << "(Listbox) Something changed." << std::endl;

  //const mitk::DataTreeFilter::ItemList* items = m_DataTreeFilter->GetItems(); //in case you want to iterate over them
}

void QmitkDataTreeFilterDemo::onCmbFilterFunctionActivated(int i)
{
  switch (i)
  {
    case 0:
      m_DataTreeFilter->SetFilter( mitk::IsGoodDataTreeNode() );
      break;
    case 1:
      m_DataTreeFilter->SetFilter( mitk::IsBaseDataType<mitk::Image>() );
      break;
    case 2:
      m_DataTreeFilter->SetFilter( mitk::IsBaseDataType<mitk::Surface>() );
      break;
    case 3:
      m_DataTreeFilter->SetFilter( mitk::IsDataTreeNode() ); // probably not what the label promises
      break;
   }
}

void QmitkDataTreeFilterDemo::onChkHierarchyToggled(bool on)
{
  if (on)
    m_DataTreeFilter->SetHierarchyHandling( mitk::DataTreeFilter::PRESERVE_HIERARCHY );
  else
    m_DataTreeFilter->SetHierarchyHandling( mitk::DataTreeFilter::FLATTEN_HIERARCHY );
}
<|endoftext|>