<commit_before>#line 2 "togo/core/string/string.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief String interface.
@ingroup lib_core_string
*/

#pragma once

#include <togo/core/config.hpp>
#include <togo/core/utility/types.hpp>
#include <togo/core/collection/fixed_array.hpp>
#include <togo/core/collection/array.hpp>
#include <togo/core/string/types.hpp>
#include <togo/core/string/string.gen_interface>

#include <cstring>

namespace togo {

namespace string {

/**
	@addtogroup lib_core_string
	@{
*/

/// Calculate size of a NUL-terminated string.
///
/// This does not include the NUL terminator.
inline unsigned size(char const* cstr) {
	return cstr ? std::strlen(cstr) : 0;
}

/// Calculate size of a string literal.
///
/// This does not include the NUL terminator if there is one.
/// If there are NULs before N, they are counted.
///
/// @warning This should only be called for string literals.
/// The C-string variant should be used for character arrays that may
/// have NULs before N.
template<unsigned N>
inline constexpr unsigned size_literal(char const (&data)[N]) {
	return N > 0 && data[N - 1] == '\0' ? N - 1 : N;
}

/// Calculate size of a fixed-capacity string.
///
/// This does not include the NUL terminator if there is one.
template<unsigned N>
inline unsigned size(FixedArray<char, N> const& string) {
	return
		!fixed_array::empty(string) && fixed_array::back(string) == '\0'
		? fixed_array::size(string) - 1
		: fixed_array::size(string)
	;
}

/// Calculate size of a string.
///
/// This does not include the NUL terminator if there is one.
inline unsigned size(Array<char> const& string) {
	return
		!array::empty(string) && array::back(string) == '\0'
		? array::size(string) - 1
		: array::size(string)
	;
}

/// Get the size of a string reference.
inline unsigned size(StringRef const& string) {
	return string.size;
}

/// Copy string.
///
/// dst will be NUL-terminated.
/// The capacity of dst (N) must be at least src.size + 1.
template<unsigned N>
inline void copy(char (&dst)[N], StringRef const& src) {
	copy(dst, N, src);
}

/// Copy string.
///
/// dst will be NUL-terminated.
/// The capacity of dst (N) must be at least src.size + 1.
template<unsigned N>
inline void copy(
	FixedArray<char, N>& dst,
	StringRef const& src
) {
	fixed_array::resize(dst, src.size + 1);
	copy(fixed_array::begin(dst), fixed_array::size(dst), src);
}

/// Copy string.
///
/// dst will be NUL-terminated.
inline void copy(
	Array<char>& dst,
	StringRef const& src
) {
	array::resize(dst, src.size + 1);
	copy(array::begin(dst), array::size(dst), src);
}

/// Append to string.
///
/// dst will be NUL-terminated.
/// The capacity of dst must be at least size + str.size + 1.
inline void append(
	char* const dst,
	unsigned const capacity,
	unsigned const size,
	StringRef const& str
) {
	copy(dst + size, capacity, str);
}

/// Append to string.
///
/// dst will be NUL-terminated.
/// The capacity of dst (N) must be at least size + str.size + 1.
template<unsigned N>
inline void append(char (&dst)[N], unsigned const size, StringRef const& str) {
	copy(dst + size, N, str);
}

/// Append to string.
///
/// dst will be NUL-terminated.
/// The capacity of dst (N) must be at least
/// string::size(dst) + str.size + 1.
template<unsigned N>
inline void append(FixedArray<char, N>& dst, StringRef const& str) {
	unsigned const size = string::size(dst);
	fixed_array::resize(dst, size + str.size + 1);
	copy(fixed_array::begin(dst) + size, str.size + 1, str);
}

/// Append to string.
///
/// dst will be NUL-terminated.
inline void append(Array<char>& dst, StringRef const& str) {
	unsigned const size = string::size(dst);
	array::resize(dst, size + str.size + 1);
	copy(array::begin(dst) + size, str.size + 1, str);
}

/// Trim trailing slashes from string.
///
/// Returns new size of string (not including NUL terminator).
template<unsigned N>
inline unsigned trim_trailing_slashes(FixedArray<char, N>& string) {
	unsigned const size = string::size(string);
	unsigned const new_size = trim_trailing_slashes(
		fixed_array::begin(string),
		size
	);
	if (new_size != size) {
		fixed_array::resize(string, new_size + 1);
	}
	return new_size;
}

/// Ensure string has a trailing slash by appending if necessary.
///
/// Returns new size of the string (not including NUL terminator).
template<unsigned N>
inline unsigned ensure_trailing_slash(FixedArray<char, N>& string) {
	unsigned const size = string::size(string);
	unsigned const new_size = ensure_trailing_slash(
		fixed_array::begin(string),
		fixed_array::capacity(string),
		size
	);
	if (new_size != size) {
		fixed_array::resize(string, new_size + 1);
	}
	return new_size;
}

/** @} */ // end of doc-group lib_core_string

} // namespace string

/// Construct to null/empty.
inline StringRef::StringRef()
	: data(nullptr)
	, size(0)
{}

/// Construct to NUL-terminated string.
inline StringRef::StringRef(char const* const cstr, cstr_tag)
	: data(cstr)
	, size(string::size(cstr))
{}

/// Construct to explicitly-sized data.
inline constexpr StringRef::StringRef(char const* const data, unsigned const size)
	: data(data)
	, size(
		data
		? (size > 0 && data[size - 1] == '\0' ? size - 1 : size)
		: 0
	)
{}

/// Construct to string literal.
///
/// @warning This should only be used for string literals.
/// The sized or C-string constructors should be used for character
/// arrays that may have empty space before N.
template<unsigned N>
inline constexpr StringRef::StringRef(char const (&data)[N])
	: StringRef(data, N)
{}

/// Construct to fixed-size character array.
template<unsigned N>
inline StringRef::StringRef(FixedArray<char, N> const& array)
	: StringRef(fixed_array::begin(array), fixed_array::size(array))
{}

/// Construct to character array.
inline StringRef::StringRef(Array<char> const& array)
	: StringRef(array::begin(array), array::size(array))
{}

/// Whether the reference has non-null data.
inline bool StringRef::valid() const {
	return data != nullptr;
}

/// Whether the reference points to a non-empty string.
inline bool StringRef::any() const {
	return size > 0;
}

/// Whether the reference points to an empty string.
inline bool StringRef::empty() const {
	return size == 0;
}

/// Get value by index.
inline char StringRef::operator[](unsigned const i) const {
	TOGO_DEBUG_ASSERTE(i < size);
	return data[i];
}

/** @cond INTERNAL */
inline char const* begin(StringRef const& str) { return str.data; }
inline char const* cbegin(StringRef const& str) { return str.data; }

inline char const* end(StringRef const& str) { return str.data + str.size; }
inline char const* cend(StringRef const& str) { return str.data + str.size; }
/** @endcond */ // INTERNAL

} // namespace togo
<commit_msg>lib/core/string: tidy.<commit_after>#line 2 "togo/core/string/string.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief String interface.
@ingroup lib_core_string
*/

#pragma once

#include <togo/core/config.hpp>
#include <togo/core/utility/types.hpp>
#include <togo/core/collection/fixed_array.hpp>
#include <togo/core/collection/array.hpp>
#include <togo/core/string/types.hpp>
#include <togo/core/string/string.gen_interface>

#include <cstring>

namespace togo {

namespace string {

/**
	@addtogroup lib_core_string
	@{
*/

/// Calculate size of a NUL-terminated string.
///
/// This does not include the NUL terminator.
inline unsigned size(char const* cstr) {
	return cstr ? std::strlen(cstr) : 0;
}

/// Calculate size of a string literal.
///
/// This does not include the NUL terminator if there is one.
/// If there are NULs before N, they are counted.
///
/// @warning This should only be called for string literals.
/// The C-string variant should be used for character arrays that may
/// have NULs before N.
template<unsigned N>
inline constexpr unsigned size_literal(char const (&data)[N]) {
	return N > 0 && data[N - 1] == '\0' ? N - 1 : N;
}

/// Calculate size of a fixed-capacity string.
///
/// This does not include the NUL terminator if there is one.
template<unsigned N>
inline unsigned size(FixedArray<char, N> const& string) {
	return
		!fixed_array::empty(string) && fixed_array::back(string) == '\0'
		? fixed_array::size(string) - 1
		: fixed_array::size(string)
	;
}

/// Calculate size of a string.
///
/// This does not include the NUL terminator if there is one.
inline unsigned size(Array<char> const& string) {
	return
		!array::empty(string) && array::back(string) == '\0'
		? array::size(string) - 1
		: array::size(string)
	;
}

/// Get the size of a string reference.
inline unsigned size(StringRef const& string) {
	return string.size;
}

/// Copy string.
///
/// dst will be NUL-terminated.
/// The capacity of dst (N) must be at least src.size + 1.
template<unsigned N>
inline void copy(char (&dst)[N], StringRef const& src) {
	string::copy(dst, N, src);
}

/// Copy string.
///
/// dst will be NUL-terminated.
/// The capacity of dst (N) must be at least src.size + 1.
template<unsigned N>
inline void copy(
	FixedArray<char, N>& dst,
	StringRef const& src
) {
	fixed_array::resize(dst, src.size + 1);
	string::copy(fixed_array::begin(dst), fixed_array::size(dst), src);
}

/// Copy string.
///
/// dst will be NUL-terminated.
inline void copy(
	Array<char>& dst,
	StringRef const& src
) {
	array::resize(dst, src.size + 1);
	string::copy(array::begin(dst), array::size(dst), src);
}

/// Append to string.
///
/// dst will be NUL-terminated.
/// The capacity of dst must be at least size + str.size + 1.
inline void append(
	char* const dst,
	unsigned const capacity,
	unsigned const size,
	StringRef const& str
) {
	string::copy(dst + size, capacity, str);
}

/// Append to string.
///
/// dst will be NUL-terminated.
/// The capacity of dst (N) must be at least size + str.size + 1.
template<unsigned N>
inline void append(char (&dst)[N], unsigned const size, StringRef const& str) {
	string::copy(dst + size, N, str);
}

/// Append to string.
///
/// dst will be NUL-terminated.
/// The capacity of dst (N) must be at least
/// string::size(dst) + str.size + 1.
template<unsigned N>
inline void append(FixedArray<char, N>& dst, StringRef const& str) {
	unsigned const size = string::size(dst);
	fixed_array::resize(dst, size + str.size + 1);
	string::copy(fixed_array::begin(dst) + size, str.size + 1, str);
}

/// Append to string.
///
/// dst will be NUL-terminated.
inline void append(Array<char>& dst, StringRef const& str) {
	unsigned const size = string::size(dst);
	array::resize(dst, size + str.size + 1);
	string::copy(array::begin(dst) + size, str.size + 1, str);
}

/// Trim trailing slashes from string.
///
/// Returns new size of string (not including NUL terminator).
template<unsigned N>
inline unsigned trim_trailing_slashes(FixedArray<char, N>& string) {
	unsigned const size = string::size(string);
	unsigned const new_size = string::trim_trailing_slashes(
		fixed_array::begin(string),
		size
	);
	if (new_size != size) {
		fixed_array::resize(string, new_size + 1);
	}
	return new_size;
}

/// Ensure string has a trailing slash by appending if necessary.
///
/// Returns new size of the string (not including NUL terminator).
template<unsigned N>
inline unsigned ensure_trailing_slash(FixedArray<char, N>& string) {
	unsigned const size = string::size(string);
	unsigned const new_size = string::ensure_trailing_slash(
		fixed_array::begin(string),
		fixed_array::capacity(string),
		size
	);
	if (new_size != size) {
		fixed_array::resize(string, new_size + 1);
	}
	return new_size;
}

/** @} */ // end of doc-group lib_core_string

} // namespace string

/// Construct to null/empty.
inline StringRef::StringRef()
	: data(nullptr)
	, size(0)
{}

/// Construct to NUL-terminated string.
inline StringRef::StringRef(char const* const cstr, cstr_tag)
	: data(cstr)
	, size(string::size(cstr))
{}

/// Construct to explicitly-sized data.
inline constexpr StringRef::StringRef(char const* const data, unsigned const size)
	: data(data)
	, size(
		data
		? (size > 0 && data[size - 1] == '\0' ? size - 1 : size)
		: 0
	)
{}

/// Construct to string literal.
///
/// @warning This should only be used for string literals.
/// The sized or C-string constructors should be used for character
/// arrays that may have empty space before N.
template<unsigned N>
inline constexpr StringRef::StringRef(char const (&data)[N])
	: StringRef(data, N)
{}

/// Construct to fixed-size character array.
template<unsigned N>
inline StringRef::StringRef(FixedArray<char, N> const& array)
	: StringRef(fixed_array::begin(array), fixed_array::size(array))
{}

/// Construct to character array.
inline StringRef::StringRef(Array<char> const& array)
	: StringRef(array::begin(array), array::size(array))
{}

/// Whether the reference has non-null data.
inline bool StringRef::valid() const {
	return data != nullptr;
}

/// Whether the reference points to a non-empty string.
inline bool StringRef::any() const {
	return size > 0;
}

/// Whether the reference points to an empty string.
inline bool StringRef::empty() const {
	return size == 0;
}

/// Get value by index.
inline char StringRef::operator[](unsigned const i) const {
	TOGO_DEBUG_ASSERTE(i < size);
	return data[i];
}

/** @cond INTERNAL */
inline char const* begin(StringRef const& str) { return str.data; }
inline char const* cbegin(StringRef const& str) { return str.data; }

inline char const* end(StringRef const& str) { return str.data + str.size; }
inline char const* cend(StringRef const& str) { return str.data + str.size; }
/** @endcond */ // INTERNAL

} // namespace togo
<|endoftext|>


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

#include "qdirectfbpixmap.h"

#include "qdirectfbscreen.h"
#include "qdirectfbpaintengine.h"

#include <QtGui/qbitmap.h>
#include <directfb.h>

static int global_ser_no = 0;

QDirectFBPixmapData::QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType)
    : QPixmapData(pixelType, DirectFBClass), QDirectFBPaintDevice(screen),
      format(QImage::Format_Invalid), alpha(false)
{
    setSerialNumber(0);
}

QDirectFBPixmapData::~QDirectFBPixmapData()
{
    unlockDirectFB();
    if (dfbSurface && QDirectFBScreen::instance())
        screen->releaseDFBSurface(dfbSurface);
}

void QDirectFBPixmapData::resize(int width, int height)
{
    if (width <= 0 || height <= 0) {
        invalidate();
        return;
    }

    format = screen->pixelFormat();
    dfbSurface = screen->createDFBSurface(QSize(width, height),
                                          format,
                                          QDirectFBScreen::TrackSurface);
    d = screen->depth();
    alpha = false;
    if (!dfbSurface) {
        invalidate();
        qWarning("QDirectFBPixmapData::resize(): Unable to allocate surface");
        return;
    }

    w = width;
    h = height;
    is_null = (w <= 0 || h <= 0);
    d = metric(QPaintDevice::PdmDepth);
    setSerialNumber(++global_ser_no);
}

// mostly duplicated from qimage.cpp (QImageData::checkForAlphaPixels)
static bool checkForAlphaPixels(const QImage &img)
{
    const uchar *bits = img.bits();
    const int bytes_per_line = img.bytesPerLine();
    const uchar *end_bits = bits + bytes_per_line;
    const int width = img.width();
    const int height = img.height();
    switch (img.format()) {
    case QImage::Format_Indexed8:
        return img.hasAlphaChannel();
    case QImage::Format_ARGB32:
    case QImage::Format_ARGB32_Premultiplied:
        for (int y=0; y<height; ++y) {
            for (int x=0; x<width; ++x) {
                if ((((uint *)bits)[x] & 0xff000000) != 0xff000000) {
                    return true;
                }
            }
            bits += bytes_per_line;
        }
        break;

    case QImage::Format_ARGB8555_Premultiplied:
    case QImage::Format_ARGB8565_Premultiplied:
        for (int y=0; y<height; ++y) {
            while (bits < end_bits) {
                if (bits[0] != 0) {
                    return true;
                }
                bits += 3;
            }
            bits = end_bits;
            end_bits += bytes_per_line;
        }
        break;

    case QImage::Format_ARGB6666_Premultiplied:
        for (int y=0; y<height; ++y) {
            while (bits < end_bits) {
                if ((bits[0] & 0xfc) != 0) {
                    return true;
                }
                bits += 3;
            }
            bits = end_bits;
            end_bits += bytes_per_line;
        }
        break;

    case QImage::Format_ARGB4444_Premultiplied:
        for (int y=0; y<height; ++y) {
            while (bits < end_bits) {
                if ((bits[0] & 0xf0) != 0) {
                    return true;
                }
                bits += 2;
            }
            bits = end_bits;
            end_bits += bytes_per_line;
        }
        break;

    default:
        break;
    }

    return false;
}

bool QDirectFBPixmapData::hasAlphaChannel(const QImage &img)
{
#ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION
    return ::checkForAlphaPixels(img);
#else
    return img.hasAlphaChannel();
#endif
}

void QDirectFBPixmapData::fromImage(const QImage &image,
                                    Qt::ImageConversionFlags flags)
{
    if (image.depth() == 1) {
        fromImage(image.convertToFormat(screen->alphaPixmapFormat()), flags);
        return;
    }

    if (image.hasAlphaChannel()
#ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION
        && (flags & Qt::NoOpaqueDetection || QDirectFBPixmapData::hasAlphaChannel(image))
#endif
        ) {
        alpha = true;
        format = screen->alphaPixmapFormat();
    } else {
        alpha = false;
        format = screen->pixelFormat();
    }

    dfbSurface = screen->createDFBSurface(image, format, QDirectFBScreen::TrackSurface|QDirectFBScreen::NoPreallocated);
    if (!dfbSurface) {
        qWarning("QDirectFBPixmapData::fromImage()");
        invalidate();
        return;
    }
    w = image.width();
    h = image.height();
    is_null = (w <= 0 || h <= 0);
    d = metric(QPaintDevice::PdmDepth);
    setSerialNumber(++global_ser_no);
#ifdef QT_NO_DIRECTFB_OPAQUE_DETECTION
    Q_UNUSED(flags);
#endif
}

void QDirectFBPixmapData::copy(const QPixmapData *data, const QRect &rect)
{
    if (data->classId() != DirectFBClass) {
        QPixmapData::copy(data, rect);
        return;
    }
    unlockDirectFB();

    const QDirectFBPixmapData *otherData = static_cast<const QDirectFBPixmapData*>(data);
    IDirectFBSurface *src = otherData->directFBSurface();
    alpha = data->hasAlphaChannel();
    format = (alpha
              ? QDirectFBScreen::instance()->alphaPixmapFormat()
              : QDirectFBScreen::instance()->pixelFormat());

    dfbSurface = screen->createDFBSurface(rect.size(), format,
                                          QDirectFBScreen::TrackSurface);
    if (!dfbSurface) {
        qWarning("QDirectFBPixmapData::copy()");
        invalidate();
        return;
    }

    if (alpha) {
        dfbSurface->Clear(dfbSurface, 0, 0, 0, 0);
        dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_BLEND_ALPHACHANNEL);
    } else {
        dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
    }
    const DFBRectangle blitRect = { rect.x(), rect.y(),
                                    rect.width(), rect.height() };
    w = rect.width();
    h = rect.height();
    d = otherData->d;
    is_null = (w <= 0 || h <= 0);
    DFBResult result = dfbSurface->Blit(dfbSurface, src, &blitRect, 0, 0);
#if (Q_DIRECTFB_VERSION >= 0x010000)
    dfbSurface->ReleaseSource(dfbSurface);
#endif
    if (result != DFB_OK) {
        DirectFBError("QDirectFBPixmapData::copy()", result);
        invalidate();
        return;
    }

    setSerialNumber(++global_ser_no);
}

static inline bool isOpaqueFormat(QImage::Format format)
{
    switch (format) {
    case QImage::Format_RGB32:
    case QImage::Format_RGB16:
    case QImage::Format_RGB666:
    case QImage::Format_RGB555:
    case QImage::Format_RGB888:
    case QImage::Format_RGB444:
        return true;
    default:
        break;
    }
    return false;
}

void QDirectFBPixmapData::fill(const QColor &color)
{
    if (!serialNumber())
        return;

    Q_ASSERT(dfbSurface);

    alpha = (color.alpha() < 255);

    if (alpha && ::isOpaqueFormat(format)) {
        QSize size;
        dfbSurface->GetSize(dfbSurface, &size.rwidth(), &size.rheight());
        screen->releaseDFBSurface(dfbSurface);
        format = screen->alphaPixmapFormat();
        dfbSurface = screen->createDFBSurface(size, screen->alphaPixmapFormat(), QDirectFBScreen::TrackSurface);
        setSerialNumber(++global_ser_no);
        if (!dfbSurface) {
            qWarning("QDirectFBPixmapData::fill()");
            invalidate();
            return;
        }
    }

    dfbSurface->Clear(dfbSurface, color.red(), color.green(), color.blue(), color.alpha());
}

QPixmap QDirectFBPixmapData::transformed(const QTransform &transform,
                                         Qt::TransformationMode mode) const
{
    QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
    if (!dfbSurface || transform.type() != QTransform::TxScale
        || mode != Qt::FastTransformation)
    {
        const QImage *image = that->buffer();
        Q_ASSERT(image);
        const QImage transformed = image->transformed(transform, mode);
        that->unlockDirectFB();
        QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType);
        data->fromImage(transformed, Qt::AutoColor);
        return QPixmap(data);
    }
    that->unlockDirectFB();

    const QSize size = transform.mapRect(QRect(0, 0, w, h)).size();
    if (size.isEmpty())
        return QPixmap();

    QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType);
    DFBSurfaceBlittingFlags flags = DSBLIT_NOFX;
    data->alpha = alpha;
    if (alpha) {
        flags = DSBLIT_BLEND_ALPHACHANNEL;
    }
    data->dfbSurface = screen->createDFBSurface(size,
                                                format,
                                                QDirectFBScreen::TrackSurface);
    if (flags & DSBLIT_BLEND_ALPHACHANNEL) {
        data->dfbSurface->Clear(data->dfbSurface, 0, 0, 0, 0);
    }
    data->dfbSurface->SetBlittingFlags(data->dfbSurface, flags);

    const DFBRectangle destRect = { 0, 0, size.width(), size.height() };
    data->dfbSurface->StretchBlit(data->dfbSurface, dfbSurface, 0, &destRect);
    data->w = size.width();
    data->h = size.height();
    data->is_null = (data->w <= 0 || data->h <= 0);

#if (Q_DIRECTFB_VERSION >= 0x010000)
    data->dfbSurface->ReleaseSource(data->dfbSurface);
#endif
    return QPixmap(data);
}

QImage QDirectFBPixmapData::toImage() const
{
    if (!dfbSurface)
        return QImage();

#if 0
    // In later versions of DirectFB one can set a flag to tell
    // DirectFB not to move the surface to videomemory. When that
    // happens we can use this (hopefully faster) codepath
#ifndef QT_NO_DIRECTFB_PREALLOCATED
    QImage ret(w, h, QDirectFBScreen::getImageFormat(dfbSurface));
    if (IDirectFBSurface *imgSurface = screen->createDFBSurface(ret, QDirectFBScreen::DontTrackSurface)) {
        if (hasAlphaChannel()) {
            imgSurface->SetBlittingFlags(imgSurface, DSBLIT_BLEND_ALPHACHANNEL);
            imgSurface->Clear(imgSurface, 0, 0, 0, 0);
        } else {
            imgSurface->SetBlittingFlags(imgSurface, DSBLIT_NOFX);
        }
        imgSurface->Blit(imgSurface, dfbSurface, 0, 0, 0);
#if (Q_DIRECTFB_VERSION >= 0x010000)
        imgSurface->ReleaseSource(imgSurface);
#endif
        imgSurface->Release(imgSurface);
        return ret;
    }
#endif
#endif

    QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
    const QImage *img = that->buffer();
    return img->copy();
}

/* This is QPixmapData::paintEngine(), not QPaintDevice::paintEngine() */

QPaintEngine *QDirectFBPixmapData::paintEngine() const
{
    if (!engine) {
        // QDirectFBPixmapData is also a QCustomRasterPaintDevice, so pass
        // that to the paint engine:
        QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
        that->engine = new QDirectFBPaintEngine(that);
    }
    return engine;
}

QImage *QDirectFBPixmapData::buffer()
{
    lockDirectFB(DSLF_READ|DSLF_WRITE);
    return lockedImage;
}

QImage * QDirectFBPixmapData::buffer(DFBSurfaceLockFlags lockFlags)
{
    lockDirectFB(lockFlags);
    return lockedImage;
}

void QDirectFBPixmapData::invalidate()
{
    setSerialNumber(0);
    alpha = false;
    d = w = h = 0;
    format = QImage::Format_Invalid;
}

<commit_msg>Release surface in QDirectFBPixmapData::invalidate<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qdirectfbpixmap.h"

#include "qdirectfbscreen.h"
#include "qdirectfbpaintengine.h"

#include <QtGui/qbitmap.h>
#include <directfb.h>

static int global_ser_no = 0;

QDirectFBPixmapData::QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType)
    : QPixmapData(pixelType, DirectFBClass), QDirectFBPaintDevice(screen),
      format(QImage::Format_Invalid), alpha(false)
{
    setSerialNumber(0);
}

QDirectFBPixmapData::~QDirectFBPixmapData()
{
    unlockDirectFB();
    if (dfbSurface && QDirectFBScreen::instance())
        screen->releaseDFBSurface(dfbSurface);
}

void QDirectFBPixmapData::resize(int width, int height)
{
    if (width <= 0 || height <= 0) {
        invalidate();
        return;
    }

    format = screen->pixelFormat();
    dfbSurface = screen->createDFBSurface(QSize(width, height),
                                          format,
                                          QDirectFBScreen::TrackSurface);
    d = screen->depth();
    alpha = false;
    if (!dfbSurface) {
        invalidate();
        qWarning("QDirectFBPixmapData::resize(): Unable to allocate surface");
        return;
    }

    w = width;
    h = height;
    is_null = (w <= 0 || h <= 0);
    d = metric(QPaintDevice::PdmDepth);
    setSerialNumber(++global_ser_no);
}

// mostly duplicated from qimage.cpp (QImageData::checkForAlphaPixels)
static bool checkForAlphaPixels(const QImage &img)
{
    const uchar *bits = img.bits();
    const int bytes_per_line = img.bytesPerLine();
    const uchar *end_bits = bits + bytes_per_line;
    const int width = img.width();
    const int height = img.height();
    switch (img.format()) {
    case QImage::Format_Indexed8:
        return img.hasAlphaChannel();
    case QImage::Format_ARGB32:
    case QImage::Format_ARGB32_Premultiplied:
        for (int y=0; y<height; ++y) {
            for (int x=0; x<width; ++x) {
                if ((((uint *)bits)[x] & 0xff000000) != 0xff000000) {
                    return true;
                }
            }
            bits += bytes_per_line;
        }
        break;

    case QImage::Format_ARGB8555_Premultiplied:
    case QImage::Format_ARGB8565_Premultiplied:
        for (int y=0; y<height; ++y) {
            while (bits < end_bits) {
                if (bits[0] != 0) {
                    return true;
                }
                bits += 3;
            }
            bits = end_bits;
            end_bits += bytes_per_line;
        }
        break;

    case QImage::Format_ARGB6666_Premultiplied:
        for (int y=0; y<height; ++y) {
            while (bits < end_bits) {
                if ((bits[0] & 0xfc) != 0) {
                    return true;
                }
                bits += 3;
            }
            bits = end_bits;
            end_bits += bytes_per_line;
        }
        break;

    case QImage::Format_ARGB4444_Premultiplied:
        for (int y=0; y<height; ++y) {
            while (bits < end_bits) {
                if ((bits[0] & 0xf0) != 0) {
                    return true;
                }
                bits += 2;
            }
            bits = end_bits;
            end_bits += bytes_per_line;
        }
        break;

    default:
        break;
    }

    return false;
}

bool QDirectFBPixmapData::hasAlphaChannel(const QImage &img)
{
#ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION
    return ::checkForAlphaPixels(img);
#else
    return img.hasAlphaChannel();
#endif
}

void QDirectFBPixmapData::fromImage(const QImage &image,
                                    Qt::ImageConversionFlags flags)
{
    if (image.depth() == 1) {
        fromImage(image.convertToFormat(screen->alphaPixmapFormat()), flags);
        return;
    }

    if (image.hasAlphaChannel()
#ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION
        && (flags & Qt::NoOpaqueDetection || QDirectFBPixmapData::hasAlphaChannel(image))
#endif
        ) {
        alpha = true;
        format = screen->alphaPixmapFormat();
    } else {
        alpha = false;
        format = screen->pixelFormat();
    }

    dfbSurface = screen->createDFBSurface(image, format, QDirectFBScreen::TrackSurface|QDirectFBScreen::NoPreallocated);
    if (!dfbSurface) {
        qWarning("QDirectFBPixmapData::fromImage()");
        invalidate();
        return;
    }
    w = image.width();
    h = image.height();
    is_null = (w <= 0 || h <= 0);
    d = metric(QPaintDevice::PdmDepth);
    setSerialNumber(++global_ser_no);
#ifdef QT_NO_DIRECTFB_OPAQUE_DETECTION
    Q_UNUSED(flags);
#endif
}

void QDirectFBPixmapData::copy(const QPixmapData *data, const QRect &rect)
{
    if (data->classId() != DirectFBClass) {
        QPixmapData::copy(data, rect);
        return;
    }
    unlockDirectFB();

    const QDirectFBPixmapData *otherData = static_cast<const QDirectFBPixmapData*>(data);
    IDirectFBSurface *src = otherData->directFBSurface();
    alpha = data->hasAlphaChannel();
    format = (alpha
              ? QDirectFBScreen::instance()->alphaPixmapFormat()
              : QDirectFBScreen::instance()->pixelFormat());

    dfbSurface = screen->createDFBSurface(rect.size(), format,
                                          QDirectFBScreen::TrackSurface);
    if (!dfbSurface) {
        qWarning("QDirectFBPixmapData::copy()");
        invalidate();
        return;
    }

    if (alpha) {
        dfbSurface->Clear(dfbSurface, 0, 0, 0, 0);
        dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_BLEND_ALPHACHANNEL);
    } else {
        dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
    }
    const DFBRectangle blitRect = { rect.x(), rect.y(),
                                    rect.width(), rect.height() };
    w = rect.width();
    h = rect.height();
    d = otherData->d;
    is_null = (w <= 0 || h <= 0);
    DFBResult result = dfbSurface->Blit(dfbSurface, src, &blitRect, 0, 0);
#if (Q_DIRECTFB_VERSION >= 0x010000)
    dfbSurface->ReleaseSource(dfbSurface);
#endif
    if (result != DFB_OK) {
        DirectFBError("QDirectFBPixmapData::copy()", result);
        invalidate();
        return;
    }

    setSerialNumber(++global_ser_no);
}

static inline bool isOpaqueFormat(QImage::Format format)
{
    switch (format) {
    case QImage::Format_RGB32:
    case QImage::Format_RGB16:
    case QImage::Format_RGB666:
    case QImage::Format_RGB555:
    case QImage::Format_RGB888:
    case QImage::Format_RGB444:
        return true;
    default:
        break;
    }
    return false;
}

void QDirectFBPixmapData::fill(const QColor &color)
{
    if (!serialNumber())
        return;

    Q_ASSERT(dfbSurface);

    alpha = (color.alpha() < 255);

    if (alpha && ::isOpaqueFormat(format)) {
        QSize size;
        dfbSurface->GetSize(dfbSurface, &size.rwidth(), &size.rheight());
        screen->releaseDFBSurface(dfbSurface);
        format = screen->alphaPixmapFormat();
        dfbSurface = screen->createDFBSurface(size, screen->alphaPixmapFormat(), QDirectFBScreen::TrackSurface);
        setSerialNumber(++global_ser_no);
        if (!dfbSurface) {
            qWarning("QDirectFBPixmapData::fill()");
            invalidate();
            return;
        }
    }

    dfbSurface->Clear(dfbSurface, color.red(), color.green(), color.blue(), color.alpha());
}

QPixmap QDirectFBPixmapData::transformed(const QTransform &transform,
                                         Qt::TransformationMode mode) const
{
    QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
    if (!dfbSurface || transform.type() != QTransform::TxScale
        || mode != Qt::FastTransformation)
    {
        const QImage *image = that->buffer();
        Q_ASSERT(image);
        const QImage transformed = image->transformed(transform, mode);
        that->unlockDirectFB();
        QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType);
        data->fromImage(transformed, Qt::AutoColor);
        return QPixmap(data);
    }
    that->unlockDirectFB();

    const QSize size = transform.mapRect(QRect(0, 0, w, h)).size();
    if (size.isEmpty())
        return QPixmap();

    QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType);
    DFBSurfaceBlittingFlags flags = DSBLIT_NOFX;
    data->alpha = alpha;
    if (alpha) {
        flags = DSBLIT_BLEND_ALPHACHANNEL;
    }
    data->dfbSurface = screen->createDFBSurface(size,
                                                format,
                                                QDirectFBScreen::TrackSurface);
    if (flags & DSBLIT_BLEND_ALPHACHANNEL) {
        data->dfbSurface->Clear(data->dfbSurface, 0, 0, 0, 0);
    }
    data->dfbSurface->SetBlittingFlags(data->dfbSurface, flags);

    const DFBRectangle destRect = { 0, 0, size.width(), size.height() };
    data->dfbSurface->StretchBlit(data->dfbSurface, dfbSurface, 0, &destRect);
    data->w = size.width();
    data->h = size.height();
    data->is_null = (data->w <= 0 || data->h <= 0);

#if (Q_DIRECTFB_VERSION >= 0x010000)
    data->dfbSurface->ReleaseSource(data->dfbSurface);
#endif
    return QPixmap(data);
}

QImage QDirectFBPixmapData::toImage() const
{
    if (!dfbSurface)
        return QImage();

#if 0
    // In later versions of DirectFB one can set a flag to tell
    // DirectFB not to move the surface to videomemory. When that
    // happens we can use this (hopefully faster) codepath
#ifndef QT_NO_DIRECTFB_PREALLOCATED
    QImage ret(w, h, QDirectFBScreen::getImageFormat(dfbSurface));
    if (IDirectFBSurface *imgSurface = screen->createDFBSurface(ret, QDirectFBScreen::DontTrackSurface)) {
        if (hasAlphaChannel()) {
            imgSurface->SetBlittingFlags(imgSurface, DSBLIT_BLEND_ALPHACHANNEL);
            imgSurface->Clear(imgSurface, 0, 0, 0, 0);
        } else {
            imgSurface->SetBlittingFlags(imgSurface, DSBLIT_NOFX);
        }
        imgSurface->Blit(imgSurface, dfbSurface, 0, 0, 0);
#if (Q_DIRECTFB_VERSION >= 0x010000)
        imgSurface->ReleaseSource(imgSurface);
#endif
        imgSurface->Release(imgSurface);
        return ret;
    }
#endif
#endif

    QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
    const QImage *img = that->buffer();
    return img->copy();
}

/* This is QPixmapData::paintEngine(), not QPaintDevice::paintEngine() */

QPaintEngine *QDirectFBPixmapData::paintEngine() const
{
    if (!engine) {
        // QDirectFBPixmapData is also a QCustomRasterPaintDevice, so pass
        // that to the paint engine:
        QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
        that->engine = new QDirectFBPaintEngine(that);
    }
    return engine;
}

QImage *QDirectFBPixmapData::buffer()
{
    lockDirectFB(DSLF_READ|DSLF_WRITE);
    return lockedImage;
}

QImage * QDirectFBPixmapData::buffer(DFBSurfaceLockFlags lockFlags)
{
    lockDirectFB(lockFlags);
    return lockedImage;
}

void QDirectFBPixmapData::invalidate()
{
    if (dfbSurface) {
        screen->releaseDFBSurface(dfbSurface);
        dfbSurface = 0;
    }
    setSerialNumber(0);
    alpha = false;
    d = w = h = 0;
    format = QImage::Format_Invalid;
}

<|endoftext|>


<commit_before><commit_msg>fixes #3665 Applying patch from jurij<commit_after><|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2011      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "OsmDatabase.h"

#include "DatabaseQuery.h"
#include "GeoDataLatLonAltBox.h"
#include "MarbleDebug.h"
#include "MarbleMath.h"
#include "MarbleLocale.h"
#include "MarbleModel.h"
#include "PositionTracking.h"

#include <QtCore/QFile>
#include <QtCore/QDataStream>
#include <QtCore/QStringList>
#include <QtCore/QRegExp>
#include <QtCore/QVariant>
#include <QtCore/QTime>

#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>

namespace Marble {

namespace {

static GeoDataCoordinates s_currentPosition;
static DatabaseQuery* s_currentQuery = 0;

bool placemarkSmallerDistance( const OsmPlacemark &a, const OsmPlacemark &b )
{
    return distanceSphere( a.longitude() * DEG2RAD, a.latitude() * DEG2RAD,
                           s_currentPosition.longitude(), s_currentPosition.latitude() )
         < distanceSphere( b.longitude() * DEG2RAD, b.latitude() * DEG2RAD,
                           s_currentPosition.longitude(), s_currentPosition.latitude() );
}

bool placemarkHigherScore( const OsmPlacemark &a, const OsmPlacemark &b )
{
    return a.matchScore( s_currentQuery ) > b.matchScore( s_currentQuery );
}

}

OsmDatabase::OsmDatabase()
{
    m_database = QSqlDatabase::addDatabase( "QSQLITE", "marble/local-osm-search" );
}

void OsmDatabase::addFile( const QString &fileName )
{
    m_databases << fileName;
}

QVector<OsmPlacemark> OsmDatabase::find( MarbleModel* model, const QString &searchTerm, const GeoDataLatLonAltBox preferred )
{
    if ( m_databases.isEmpty() ) {
        return QVector<OsmPlacemark>();
    }

    DatabaseQuery userQuery( model, searchTerm, preferred );

    QVector<OsmPlacemark> result;
    QTime timer;
    timer.start();
    foreach( const QString &databaseFile, m_databases ) {
        m_database.setDatabaseName( databaseFile );
        if ( !m_database.open() ) {
            mDebug() << "Failed to connect to database " << databaseFile;
        }

        QString regionRestriction;
        if ( !userQuery.region().isEmpty() ) {
            // Nested set model to support region hierarchies, see http://en.wikipedia.org/wiki/Nested_set_model
            QSqlQuery regionsQuery( "SELECT lft, rgt FROM regions WHERE name LIKE '%" + userQuery.region() + "%';", m_database );
            if ( regionsQuery.lastError().isValid() ) {
                mDebug() << "Error when executing query" << regionsQuery.executedQuery();
                mDebug() << "Sql reports" << regionsQuery.lastError();
            }
            regionRestriction = " AND (";
            bool first = true;
            while ( regionsQuery.next() ) {
                if ( first ) {
                    first = false;
                } else {
                    regionRestriction += " OR ";
                }
                regionRestriction += " (regions.lft >= " + regionsQuery.value( 0 ).toString();
                regionRestriction += " AND regions.lft <= " + regionsQuery.value( 1 ).toString() + ")";
            }
            regionRestriction += ")";

            if ( first ) {
                continue;
            }
        }

        QString queryString;

        queryString = " SELECT regions.name,"
                " places.name, places.number,"
                " places.category, places.lon, places.lat"
                " FROM regions, places";

        if ( userQuery.queryType() == DatabaseQuery::CategorySearch ) {
            queryString += " WHERE regions.id = places.region AND places.category = %1";
            queryString = queryString.arg( (qint32) userQuery.category() );
            if ( userQuery.resultFormat() == DatabaseQuery::DistanceFormat && userQuery.region().isEmpty() ) {
                queryString += " ORDER BY ((places.lat-%1)*(places.lat-%1)+(places.lon-%2)*(places.lon-%2))";
                GeoDataCoordinates position = userQuery.position();
                queryString = queryString.arg( position.latitude( GeoDataCoordinates::Degree ), 0, 'f', 8 )
                        .arg( position.longitude( GeoDataCoordinates::Degree ), 0, 'f', 8 );
            } else {
                queryString += regionRestriction;
            }
        } else if ( userQuery.queryType() == DatabaseQuery::BroadSearch ) {
            queryString += " WHERE regions.id = places.region"
                    " AND places.name " + wildcardQuery( searchTerm );
        } else {
            queryString += " WHERE regions.id = places.region"
                    "   AND places.name " + wildcardQuery( userQuery.street() );
            if ( !userQuery.houseNumber().isEmpty() ) {
                queryString += " AND places.number " + wildcardQuery( userQuery.houseNumber() );
            } else {
                queryString += " AND places.number IS NULL";
            }
            queryString += regionRestriction;
        }

        queryString += " LIMIT 50;";

        /** @todo: sort/filter results from several databases */

        QSqlQuery query( m_database );
        query.setForwardOnly( true );
        if ( !query.exec( queryString ) ) {
            mDebug() << "Failed to execute query" << query.lastError();
            return result;
        }

        while ( query.next() ) {
            OsmPlacemark placemark;
            if ( userQuery.resultFormat() == DatabaseQuery::DistanceFormat ) {
                GeoDataCoordinates coordinates( query.value(4).toFloat(), query.value(5).toFloat(), 0.0, GeoDataCoordinates::Degree );
                placemark.setAdditionalInformation( formatDistance( coordinates, userQuery.position() ) );
            } else {
                placemark.setAdditionalInformation( query.value( 0 ).toString() );
            }
            placemark.setName( query.value(1).toString() );
            placemark.setHouseNumber( query.value(2).toString() );
            placemark.setCategory( (OsmPlacemark::OsmCategory) query.value(3).toInt() );
            placemark.setLongitude( query.value(4).toFloat() );
            placemark.setLatitude( query.value(5).toFloat() );
            result.push_back( placemark );
        }

        // mDebug() << "Query string: " << queryString;
    }

    mDebug() << "Offline OSM search query took " << timer.elapsed() << " ms.";

    qSort( result.begin(), result.end() );
    unique( result );

    if ( userQuery.resultFormat() == DatabaseQuery::DistanceFormat ) {
        s_currentPosition = model->positionTracking()->currentLocation();
        qSort( result.begin(), result.end(), placemarkSmallerDistance );
    } else {
        s_currentQuery = &userQuery;
        qSort( result.begin(), result.end(), placemarkHigherScore );
        s_currentQuery = 0;
    }

    if ( result.size() > 50 ) {
        result.remove( 50, result.size()-50 );
    }

    return result;
}

void OsmDatabase::unique( QVector<OsmPlacemark> &placemarks ) const
{
    for ( int i=1; i<placemarks.size(); ++i ) {
        if ( placemarks[i-1] == placemarks[i] ) {
            placemarks.remove( i );
            --i;
        }
    }
}

QString OsmDatabase::formatDistance( const GeoDataCoordinates &a, const GeoDataCoordinates &b ) const
{
    qreal distance = EARTH_RADIUS * distanceSphere( a, b);

    int precision = 0;
    QString distanceUnit = "m";

    if ( MarbleGlobal::getInstance()->locale()->measurementSystem() == QLocale::ImperialSystem ) {
        precision = 1;
        distanceUnit = "mi";
        distance *= METER2KM;
        distance *= KM2MI;
    } else {
        if ( distance >= 1000 ) {
            distance /= 1000;
            distanceUnit = "km";
            precision = 1;
        } else if ( distance >= 200 ) {
            distance = 50 * qRound( distance / 50 );
        } else if ( distance >= 100 ) {
            distance = 25 * qRound( distance / 25 );
        } else {
            distance = 10 * qRound( distance / 10 );
        }
    }

    QString const fuzzyDistance = QString( "%1 %2" ).arg( distance, 0, 'f', precision ).arg( distanceUnit );

    int direction = 180 + bearing( a, b ) * RAD2DEG;

    QString heading = QObject::tr( "north" );
    if ( direction > 337 ) {
        heading = QObject::tr( "north" );
    } else if ( direction > 292 ) {
        heading = QObject::tr( "north-west" );
    } else if ( direction > 247 ) {
        heading = QObject::tr( "west" );
    } else if ( direction > 202 ) {
        heading = QObject::tr( "south-west" );
    } else if ( direction > 157 ) {
        heading = QObject::tr( "south" );
    } else if ( direction > 112 ) {
        heading = QObject::tr( "south-east" );
    } else if ( direction > 67 ) {
        heading = QObject::tr( "east" );
    } else if ( direction > 22 ) {
        heading = QObject::tr( "north-east" );
    }

    return fuzzyDistance + " " + heading;
}

qreal OsmDatabase::bearing( const GeoDataCoordinates &a, const GeoDataCoordinates &b ) const
{
    qreal delta = b.longitude() - a.longitude();
    qreal lat1 = a.latitude();
    qreal lat2 = b.latitude();
    return fmod( atan2( sin ( delta ) * cos ( lat2 ),
                       cos( lat1 ) * sin( lat2 ) - sin( lat1 ) * cos( lat2 ) * cos ( delta ) ), 2 * M_PI );
}

QString OsmDatabase::wildcardQuery( const QString &term ) const
{
    QString result = term;
    if ( term.contains( '*' ) ) {
        return " LIKE '" + result.replace( '*', '%' ) + "'";
    } else {
        return " = '" + result + "'";
    }
}

void OsmDatabase::clear()
{
    m_databases.clear();
}

}
<commit_msg>local-osm-search: fix position use<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2011      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "OsmDatabase.h"

#include "DatabaseQuery.h"
#include "GeoDataLatLonAltBox.h"
#include "MarbleDebug.h"
#include "MarbleMath.h"
#include "MarbleLocale.h"
#include "MarbleModel.h"
#include "PositionTracking.h"

#include <QtCore/QFile>
#include <QtCore/QDataStream>
#include <QtCore/QStringList>
#include <QtCore/QRegExp>
#include <QtCore/QVariant>
#include <QtCore/QTime>

#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>

namespace Marble {

namespace {

static GeoDataCoordinates s_currentPosition;
static DatabaseQuery* s_currentQuery = 0;

bool placemarkSmallerDistance( const OsmPlacemark &a, const OsmPlacemark &b )
{
    return distanceSphere( a.longitude() * DEG2RAD, a.latitude() * DEG2RAD,
                           s_currentPosition.longitude(), s_currentPosition.latitude() )
         < distanceSphere( b.longitude() * DEG2RAD, b.latitude() * DEG2RAD,
                           s_currentPosition.longitude(), s_currentPosition.latitude() );
}

bool placemarkHigherScore( const OsmPlacemark &a, const OsmPlacemark &b )
{
    return a.matchScore( s_currentQuery ) > b.matchScore( s_currentQuery );
}

}

OsmDatabase::OsmDatabase()
{
    m_database = QSqlDatabase::addDatabase( "QSQLITE", "marble/local-osm-search" );
}

void OsmDatabase::addFile( const QString &fileName )
{
    m_databases << fileName;
}

QVector<OsmPlacemark> OsmDatabase::find( MarbleModel* model, const QString &searchTerm, const GeoDataLatLonAltBox preferred )
{
    if ( m_databases.isEmpty() ) {
        return QVector<OsmPlacemark>();
    }

    DatabaseQuery userQuery( model, searchTerm, preferred );

    QVector<OsmPlacemark> result;
    QTime timer;
    timer.start();
    foreach( const QString &databaseFile, m_databases ) {
        m_database.setDatabaseName( databaseFile );
        if ( !m_database.open() ) {
            mDebug() << "Failed to connect to database " << databaseFile;
        }

        QString regionRestriction;
        if ( !userQuery.region().isEmpty() ) {
            // Nested set model to support region hierarchies, see http://en.wikipedia.org/wiki/Nested_set_model
            QSqlQuery regionsQuery( "SELECT lft, rgt FROM regions WHERE name LIKE '%" + userQuery.region() + "%';", m_database );
            if ( regionsQuery.lastError().isValid() ) {
                mDebug() << "Error when executing query" << regionsQuery.executedQuery();
                mDebug() << "Sql reports" << regionsQuery.lastError();
            }
            regionRestriction = " AND (";
            bool first = true;
            while ( regionsQuery.next() ) {
                if ( first ) {
                    first = false;
                } else {
                    regionRestriction += " OR ";
                }
                regionRestriction += " (regions.lft >= " + regionsQuery.value( 0 ).toString();
                regionRestriction += " AND regions.lft <= " + regionsQuery.value( 1 ).toString() + ")";
            }
            regionRestriction += ")";

            if ( first ) {
                continue;
            }
        }

        QString queryString;

        queryString = " SELECT regions.name,"
                " places.name, places.number,"
                " places.category, places.lon, places.lat"
                " FROM regions, places";

        if ( userQuery.queryType() == DatabaseQuery::CategorySearch ) {
            queryString += " WHERE regions.id = places.region AND places.category = %1";
            queryString = queryString.arg( (qint32) userQuery.category() );
            if ( userQuery.resultFormat() == DatabaseQuery::DistanceFormat && userQuery.region().isEmpty() ) {
                queryString += " ORDER BY ((places.lat-%1)*(places.lat-%1)+(places.lon-%2)*(places.lon-%2))";
                GeoDataCoordinates position = userQuery.position();
                queryString = queryString.arg( position.latitude( GeoDataCoordinates::Degree ), 0, 'f', 8 )
                        .arg( position.longitude( GeoDataCoordinates::Degree ), 0, 'f', 8 );
            } else {
                queryString += regionRestriction;
            }
        } else if ( userQuery.queryType() == DatabaseQuery::BroadSearch ) {
            queryString += " WHERE regions.id = places.region"
                    " AND places.name " + wildcardQuery( searchTerm );
        } else {
            queryString += " WHERE regions.id = places.region"
                    "   AND places.name " + wildcardQuery( userQuery.street() );
            if ( !userQuery.houseNumber().isEmpty() ) {
                queryString += " AND places.number " + wildcardQuery( userQuery.houseNumber() );
            } else {
                queryString += " AND places.number IS NULL";
            }
            queryString += regionRestriction;
        }

        queryString += " LIMIT 50;";

        /** @todo: sort/filter results from several databases */

        QSqlQuery query( m_database );
        query.setForwardOnly( true );
        if ( !query.exec( queryString ) ) {
            mDebug() << "Failed to execute query" << query.lastError();
            return result;
        }

        while ( query.next() ) {
            OsmPlacemark placemark;
            if ( userQuery.resultFormat() == DatabaseQuery::DistanceFormat ) {
                GeoDataCoordinates coordinates( query.value(4).toFloat(), query.value(5).toFloat(), 0.0, GeoDataCoordinates::Degree );
                placemark.setAdditionalInformation( formatDistance( coordinates, userQuery.position() ) );
            } else {
                placemark.setAdditionalInformation( query.value( 0 ).toString() );
            }
            placemark.setName( query.value(1).toString() );
            placemark.setHouseNumber( query.value(2).toString() );
            placemark.setCategory( (OsmPlacemark::OsmCategory) query.value(3).toInt() );
            placemark.setLongitude( query.value(4).toFloat() );
            placemark.setLatitude( query.value(5).toFloat() );
            result.push_back( placemark );
        }

        // mDebug() << "Query string: " << queryString;
    }

    mDebug() << "Offline OSM search query took " << timer.elapsed() << " ms.";

    qSort( result.begin(), result.end() );
    unique( result );

    if ( userQuery.resultFormat() == DatabaseQuery::DistanceFormat ) {
        s_currentPosition = userQuery.position();
        qSort( result.begin(), result.end(), placemarkSmallerDistance );
    } else {
        s_currentQuery = &userQuery;
        qSort( result.begin(), result.end(), placemarkHigherScore );
        s_currentQuery = 0;
    }

    if ( result.size() > 50 ) {
        result.remove( 50, result.size()-50 );
    }

    return result;
}

void OsmDatabase::unique( QVector<OsmPlacemark> &placemarks ) const
{
    for ( int i=1; i<placemarks.size(); ++i ) {
        if ( placemarks[i-1] == placemarks[i] ) {
            placemarks.remove( i );
            --i;
        }
    }
}

QString OsmDatabase::formatDistance( const GeoDataCoordinates &a, const GeoDataCoordinates &b ) const
{
    qreal distance = EARTH_RADIUS * distanceSphere( a, b);

    int precision = 0;
    QString distanceUnit = "m";

    if ( MarbleGlobal::getInstance()->locale()->measurementSystem() == QLocale::ImperialSystem ) {
        precision = 1;
        distanceUnit = "mi";
        distance *= METER2KM;
        distance *= KM2MI;
    } else {
        if ( distance >= 1000 ) {
            distance /= 1000;
            distanceUnit = "km";
            precision = 1;
        } else if ( distance >= 200 ) {
            distance = 50 * qRound( distance / 50 );
        } else if ( distance >= 100 ) {
            distance = 25 * qRound( distance / 25 );
        } else {
            distance = 10 * qRound( distance / 10 );
        }
    }

    QString const fuzzyDistance = QString( "%1 %2" ).arg( distance, 0, 'f', precision ).arg( distanceUnit );

    int direction = 180 + bearing( a, b ) * RAD2DEG;

    QString heading = QObject::tr( "north" );
    if ( direction > 337 ) {
        heading = QObject::tr( "north" );
    } else if ( direction > 292 ) {
        heading = QObject::tr( "north-west" );
    } else if ( direction > 247 ) {
        heading = QObject::tr( "west" );
    } else if ( direction > 202 ) {
        heading = QObject::tr( "south-west" );
    } else if ( direction > 157 ) {
        heading = QObject::tr( "south" );
    } else if ( direction > 112 ) {
        heading = QObject::tr( "south-east" );
    } else if ( direction > 67 ) {
        heading = QObject::tr( "east" );
    } else if ( direction > 22 ) {
        heading = QObject::tr( "north-east" );
    }

    return fuzzyDistance + " " + heading;
}

qreal OsmDatabase::bearing( const GeoDataCoordinates &a, const GeoDataCoordinates &b ) const
{
    qreal delta = b.longitude() - a.longitude();
    qreal lat1 = a.latitude();
    qreal lat2 = b.latitude();
    return fmod( atan2( sin ( delta ) * cos ( lat2 ),
                       cos( lat1 ) * sin( lat2 ) - sin( lat1 ) * cos( lat2 ) * cos ( delta ) ), 2 * M_PI );
}

QString OsmDatabase::wildcardQuery( const QString &term ) const
{
    QString result = term;
    if ( term.contains( '*' ) ) {
        return " LIKE '" + result.replace( '*', '%' ) + "'";
    } else {
        return " = '" + result + "'";
    }
}

void OsmDatabase::clear()
{
    m_databases.clear();
}

}
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/base/logging.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/objects/xenumerator.h"
#include "xenia/kernel/objects/xuser_module.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/util/xex2.h"
#include "xenia/kernel/xam_private.h"
#include "xenia/xbox.h"

namespace xe {
namespace kernel {

SHIM_CALL XamGetSystemVersion_shim(PPCContext* ppc_state, KernelState* state) {
  XELOGD("XamGetSystemVersion()");
  // eh, just picking one. If we go too low we may break new games, but
  // this value seems to be used for conditionally loading symbols and if
  // we pretend to be old we have less to worry with implementing.
  // 0x200A3200
  // 0x20096B00
  SHIM_SET_RETURN_64(0);
}

SHIM_CALL XGetAVPack_shim(PPCContext* ppc_state, KernelState* state) {
  // DWORD
  // Not sure what the values are for this, but 6 is VGA.
  // Other likely values are 3/4/8 for HDMI or something.
  // Games seem to use this as a PAL check - if the result is not 3/4/6/8
  // they explode with errors if not in PAL mode.
  SHIM_SET_RETURN_64(6);
}

SHIM_CALL XGetGameRegion_shim(PPCContext* ppc_state, KernelState* state) {
  XELOGD("XGetGameRegion()");

  SHIM_SET_RETURN_64(XEX_REGION_ALL);
}

SHIM_CALL XGetLanguage_shim(PPCContext* ppc_state, KernelState* state) {
  XELOGD("XGetLanguage()");

  uint32_t desired_language = X_LANGUAGE_ENGLISH;

  // Switch the language based on game region.
  // TODO(benvanik): pull from xex header.
  uint32_t game_region = XEX_REGION_NTSCU;
  if (game_region & XEX_REGION_NTSCU) {
    desired_language = X_LANGUAGE_ENGLISH;
  } else if (game_region & XEX_REGION_NTSCJ) {
    desired_language = X_LANGUAGE_JAPANESE;
  }
  // Add more overrides?

  SHIM_SET_RETURN_64(desired_language);
}

SHIM_CALL XamVoiceIsActiveProcess_shim(PPCContext* ppc_state,
                                       KernelState* state) {
  XELOGD("XamVoiceIsActiveProcess()");
  // Returning 0 here will short-circuit a bunch of voice stuff.
  SHIM_SET_RETURN_32(0);
}

SHIM_CALL XamGetExecutionId_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t info_ptr = SHIM_GET_ARG_32(0);

  XELOGD("XamGetExecutionId(%.8X)", info_ptr);

  auto module = state->GetExecutableModule();
  assert_not_null(module);

  SHIM_SET_MEM_32(info_ptr, module->execution_info_ptr());

  module->Release();

  SHIM_SET_RETURN_32(0);
}

SHIM_CALL XamLoaderGetLaunchDataSize_shim(PPCContext* ppc_state,
                                          KernelState* state) {
  uint32_t size_ptr = SHIM_GET_ARG_32(0);

  XELOGD("XamLoaderGetLaunchDataSize(%.8X)", size_ptr);

  SHIM_SET_MEM_32(size_ptr, 0);

  SHIM_SET_RETURN_64(0);
}

SHIM_CALL XamLoaderGetLaunchData_shim(PPCContext* ppc_state,
                                      KernelState* state) {
  uint32_t buffer_ptr = SHIM_GET_ARG_32(0);
  uint32_t buffer_size = SHIM_GET_ARG_32(1);

  XELOGD("XamLoaderGetLaunchData(%.8X, %d)", buffer_ptr, buffer_size);

  SHIM_SET_RETURN_64(0);
}

SHIM_CALL XamLoaderLaunchTitle_shim(PPCContext* ppc_state, KernelState* state) {
  XELOGD("XamLoaderLaunchTitle(?)");
  assert_always();
}

SHIM_CALL XamLoaderTerminateTitle_shim(PPCContext* ppc_state,
                                       KernelState* state) {
  XELOGD("XamLoaderTerminateTitle()");
  assert_always();
}

SHIM_CALL XamAlloc_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t unk = SHIM_GET_ARG_32(0);
  uint32_t size = SHIM_GET_ARG_32(1);
  uint32_t out_ptr = SHIM_GET_ARG_32(2);

  XELOGD("XamAlloc(%d, %d, %.8X)", unk, size, out_ptr);

  assert_true(unk == 0);

  // Allocate from the heap. Not sure why XAM does this specially, perhaps
  // it keeps stuff in a separate heap?
  uint32_t ptr = state->memory()->SystemHeapAlloc(size);
  SHIM_SET_MEM_32(out_ptr, ptr);

  SHIM_SET_RETURN_32(X_ERROR_SUCCESS);
}

SHIM_CALL XamFree_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t ptr = SHIM_GET_ARG_32(0);

  XELOGD("XamFree(%.8X)", ptr);

  state->memory()->SystemHeapFree(ptr);

  SHIM_SET_RETURN_32(X_ERROR_SUCCESS);
}

SHIM_CALL XamEnumerate_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t handle = SHIM_GET_ARG_32(0);
  uint32_t zero = SHIM_GET_ARG_32(1);
  uint32_t buffer_ptr = SHIM_GET_ARG_32(2);
  uint32_t buffer_length = SHIM_GET_ARG_32(3);
  uint32_t item_count_ptr = SHIM_GET_ARG_32(4);
  uint32_t overlapped_ptr = SHIM_GET_ARG_32(5);

  assert_true(zero == 0);

  XELOGD("XamEnumerate(%.8X, %d, %.8X, %d, %.8X, %.8X)", handle, zero,
         buffer_ptr, buffer_length, item_count_ptr, overlapped_ptr);

  XEnumerator* e = nullptr;
  if (XFAILED(state->object_table()->GetObject(handle, (XObject**)&e))) {
    SHIM_SET_RETURN_64(X_ERROR_INVALID_HANDLE);
    return;
  }

  auto item_count = e->item_count();
  e->WriteItems(SHIM_MEM_ADDR(buffer_ptr));

  X_RESULT result = item_count ? X_ERROR_SUCCESS : X_ERROR_NO_MORE_FILES;
  if (item_count_ptr) {
    assert_zero(overlapped_ptr);
    SHIM_SET_MEM_32(item_count_ptr, item_count);
  } else if (overlapped_ptr) {
    assert_zero(item_count_ptr);
    state->CompleteOverlappedImmediate(overlapped_ptr, result, item_count);
    result = X_ERROR_IO_PENDING;
  } else {
    assert_always();
    result = X_ERROR_INVALID_PARAMETER;
  }

  e->Release();

  SHIM_SET_RETURN_64(result);
}

}  // namespace kernel
}  // namespace xe

void xe::kernel::xam::RegisterInfoExports(
    xe::cpu::ExportResolver* export_resolver, KernelState* state) {
  SHIM_SET_MAPPING("xam.xex", XamGetSystemVersion, state);
  SHIM_SET_MAPPING("xam.xex", XGetAVPack, state);
  SHIM_SET_MAPPING("xam.xex", XGetGameRegion, state);
  SHIM_SET_MAPPING("xam.xex", XGetLanguage, state);

  SHIM_SET_MAPPING("xam.xex", XamVoiceIsActiveProcess, state);

  SHIM_SET_MAPPING("xam.xex", XamGetExecutionId, state);
  SHIM_SET_MAPPING("xam.xex", XamLoaderGetLaunchDataSize, state);
  SHIM_SET_MAPPING("xam.xex", XamLoaderGetLaunchData, state);
  SHIM_SET_MAPPING("xam.xex", XamLoaderLaunchTitle, state);
  SHIM_SET_MAPPING("xam.xex", XamLoaderTerminateTitle, state);

  SHIM_SET_MAPPING("xam.xex", XamAlloc, state);
  SHIM_SET_MAPPING("xam.xex", XamFree, state);

  SHIM_SET_MAPPING("xam.xex", XamEnumerate, state);
}
<commit_msg>XamLoaderLaunchTitle log parameters<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/base/logging.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/objects/xenumerator.h"
#include "xenia/kernel/objects/xuser_module.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/util/xex2.h"
#include "xenia/kernel/xam_private.h"
#include "xenia/xbox.h"

namespace xe {
namespace kernel {

SHIM_CALL XamGetSystemVersion_shim(PPCContext* ppc_state, KernelState* state) {
  XELOGD("XamGetSystemVersion()");
  // eh, just picking one. If we go too low we may break new games, but
  // this value seems to be used for conditionally loading symbols and if
  // we pretend to be old we have less to worry with implementing.
  // 0x200A3200
  // 0x20096B00
  SHIM_SET_RETURN_64(0);
}

SHIM_CALL XGetAVPack_shim(PPCContext* ppc_state, KernelState* state) {
  // DWORD
  // Not sure what the values are for this, but 6 is VGA.
  // Other likely values are 3/4/8 for HDMI or something.
  // Games seem to use this as a PAL check - if the result is not 3/4/6/8
  // they explode with errors if not in PAL mode.
  SHIM_SET_RETURN_64(6);
}

SHIM_CALL XGetGameRegion_shim(PPCContext* ppc_state, KernelState* state) {
  XELOGD("XGetGameRegion()");

  SHIM_SET_RETURN_64(XEX_REGION_ALL);
}

SHIM_CALL XGetLanguage_shim(PPCContext* ppc_state, KernelState* state) {
  XELOGD("XGetLanguage()");

  uint32_t desired_language = X_LANGUAGE_ENGLISH;

  // Switch the language based on game region.
  // TODO(benvanik): pull from xex header.
  uint32_t game_region = XEX_REGION_NTSCU;
  if (game_region & XEX_REGION_NTSCU) {
    desired_language = X_LANGUAGE_ENGLISH;
  } else if (game_region & XEX_REGION_NTSCJ) {
    desired_language = X_LANGUAGE_JAPANESE;
  }
  // Add more overrides?

  SHIM_SET_RETURN_64(desired_language);
}

SHIM_CALL XamVoiceIsActiveProcess_shim(PPCContext* ppc_state,
                                       KernelState* state) {
  XELOGD("XamVoiceIsActiveProcess()");
  // Returning 0 here will short-circuit a bunch of voice stuff.
  SHIM_SET_RETURN_32(0);
}

SHIM_CALL XamGetExecutionId_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t info_ptr = SHIM_GET_ARG_32(0);

  XELOGD("XamGetExecutionId(%.8X)", info_ptr);

  auto module = state->GetExecutableModule();
  assert_not_null(module);

  SHIM_SET_MEM_32(info_ptr, module->execution_info_ptr());

  module->Release();

  SHIM_SET_RETURN_32(0);
}

SHIM_CALL XamLoaderGetLaunchDataSize_shim(PPCContext* ppc_state,
                                          KernelState* state) {
  uint32_t size_ptr = SHIM_GET_ARG_32(0);

  XELOGD("XamLoaderGetLaunchDataSize(%.8X)", size_ptr);

  SHIM_SET_MEM_32(size_ptr, 0);

  SHIM_SET_RETURN_64(0);
}

SHIM_CALL XamLoaderGetLaunchData_shim(PPCContext* ppc_state,
                                      KernelState* state) {
  uint32_t buffer_ptr = SHIM_GET_ARG_32(0);
  uint32_t buffer_size = SHIM_GET_ARG_32(1);

  XELOGD("XamLoaderGetLaunchData(%.8X, %d)", buffer_ptr, buffer_size);

  SHIM_SET_RETURN_64(0);
}

SHIM_CALL XamLoaderLaunchTitle_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t name_ptr = SHIM_GET_ARG_32(0);
  const char* name = (const char*)SHIM_MEM_ADDR(name_ptr);
  uint32_t unk2 = SHIM_GET_ARG_32(1);

  XELOGD("XamLoaderLaunchTitle(%.8X(%s), %.8X)", name_ptr, name, unk2);
  assert_always();
}

SHIM_CALL XamLoaderTerminateTitle_shim(PPCContext* ppc_state,
                                       KernelState* state) {
  XELOGD("XamLoaderTerminateTitle()");
  assert_always();
}

SHIM_CALL XamAlloc_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t unk = SHIM_GET_ARG_32(0);
  uint32_t size = SHIM_GET_ARG_32(1);
  uint32_t out_ptr = SHIM_GET_ARG_32(2);

  XELOGD("XamAlloc(%d, %d, %.8X)", unk, size, out_ptr);

  assert_true(unk == 0);

  // Allocate from the heap. Not sure why XAM does this specially, perhaps
  // it keeps stuff in a separate heap?
  uint32_t ptr = state->memory()->SystemHeapAlloc(size);
  SHIM_SET_MEM_32(out_ptr, ptr);

  SHIM_SET_RETURN_32(X_ERROR_SUCCESS);
}

SHIM_CALL XamFree_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t ptr = SHIM_GET_ARG_32(0);

  XELOGD("XamFree(%.8X)", ptr);

  state->memory()->SystemHeapFree(ptr);

  SHIM_SET_RETURN_32(X_ERROR_SUCCESS);
}

SHIM_CALL XamEnumerate_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t handle = SHIM_GET_ARG_32(0);
  uint32_t zero = SHIM_GET_ARG_32(1);
  uint32_t buffer_ptr = SHIM_GET_ARG_32(2);
  uint32_t buffer_length = SHIM_GET_ARG_32(3);
  uint32_t item_count_ptr = SHIM_GET_ARG_32(4);
  uint32_t overlapped_ptr = SHIM_GET_ARG_32(5);

  assert_true(zero == 0);

  XELOGD("XamEnumerate(%.8X, %d, %.8X, %d, %.8X, %.8X)", handle, zero,
         buffer_ptr, buffer_length, item_count_ptr, overlapped_ptr);

  XEnumerator* e = nullptr;
  if (XFAILED(state->object_table()->GetObject(handle, (XObject**)&e))) {
    SHIM_SET_RETURN_64(X_ERROR_INVALID_HANDLE);
    return;
  }

  auto item_count = e->item_count();
  e->WriteItems(SHIM_MEM_ADDR(buffer_ptr));

  X_RESULT result = item_count ? X_ERROR_SUCCESS : X_ERROR_NO_MORE_FILES;
  if (item_count_ptr) {
    assert_zero(overlapped_ptr);
    SHIM_SET_MEM_32(item_count_ptr, item_count);
  } else if (overlapped_ptr) {
    assert_zero(item_count_ptr);
    state->CompleteOverlappedImmediate(overlapped_ptr, result, item_count);
    result = X_ERROR_IO_PENDING;
  } else {
    assert_always();
    result = X_ERROR_INVALID_PARAMETER;
  }

  e->Release();

  SHIM_SET_RETURN_64(result);
}

}  // namespace kernel
}  // namespace xe

void xe::kernel::xam::RegisterInfoExports(
    xe::cpu::ExportResolver* export_resolver, KernelState* state) {
  SHIM_SET_MAPPING("xam.xex", XamGetSystemVersion, state);
  SHIM_SET_MAPPING("xam.xex", XGetAVPack, state);
  SHIM_SET_MAPPING("xam.xex", XGetGameRegion, state);
  SHIM_SET_MAPPING("xam.xex", XGetLanguage, state);

  SHIM_SET_MAPPING("xam.xex", XamVoiceIsActiveProcess, state);

  SHIM_SET_MAPPING("xam.xex", XamGetExecutionId, state);
  SHIM_SET_MAPPING("xam.xex", XamLoaderGetLaunchDataSize, state);
  SHIM_SET_MAPPING("xam.xex", XamLoaderGetLaunchData, state);
  SHIM_SET_MAPPING("xam.xex", XamLoaderLaunchTitle, state);
  SHIM_SET_MAPPING("xam.xex", XamLoaderTerminateTitle, state);

  SHIM_SET_MAPPING("xam.xex", XamAlloc, state);
  SHIM_SET_MAPPING("xam.xex", XamFree, state);

  SHIM_SET_MAPPING("xam.xex", XamEnumerate, state);
}
<|endoftext|>


<commit_before>/*
	Copyright (C) 2003-2013 by Kristina Simpson <sweet.kristas@gmail.com>

	This software is provided 'as-is', without any express or implied
	warranty. In no event will the authors be held liable for any damages
	arising from the use of this software.

	Permission is granted to anyone to use this software for any purpose,
	including commercial applications, and to alter it and redistribute it
	freely, subject to the following restrictions:

	   1. The origin of this software must not be misrepresented; you must not
	   claim that you wrote the original software. If you use this software
	   in a product, an acknowledgment in the product documentation would be
	   appreciated but is not required.

	   2. Altered source versions must be plainly marked as such, and must not be
	   misrepresented as being the original software.

	   3. This notice may not be removed or altered from any source
	   distribution.
*/

#include "solid_renderable.hpp"
#include "xhtml_line_box.hpp"
#include "xhtml_layout_engine.hpp"
#include "xhtml_text_box.hpp"

namespace xhtml
{
	LineBox::LineBox(BoxPtr parent, const point& cursor)
		: Box(BoxId::LINE, parent, nullptr),
		  starting_x_(0),
		  cursor_(cursor)
	{
	}

	std::string LineBox::toString() const
	{
		std::ostringstream ss;
		ss << "LineBox: " << getDimensions().content_;
		return ss.str();
	}

	void LineBox::reflowChildren(LayoutEngine& eng, const Dimensions& containing)
	{
		FixedPoint lh = eng.getLineHeight();
		FixedPoint width = eng.getWidthAtPosition(cursor_.y + eng.getOffset().y, containing.content_.width) - cursor_.x;

		auto children = getChildren();
		clearChildren();
		for(auto& child : children) {
			if(child->id() == BoxId::TEXT) {
				auto txt = std::dynamic_pointer_cast<TextBox>(child);
				ASSERT_LOG(txt != nullptr, "Something went wrong child box with id TEXT couldn't be cast to Text box");
				TextPtr tnode = txt->getText();
				auto it = tnode->begin();

				while(it != tnode->end()) {
					it = txt->reflow(eng, cursor_, it);

					LinePtr line = txt->getLine();
					if(line != nullptr && !line->line.empty()) {
						txt->setContentX(cursor_.x);
						txt->setContentY(cursor_.y);

						FixedPoint x_inc = txt->getWidth() + txt->getMBPWidth();
						cursor_.x += x_inc;
						width -= x_inc;
						addChild(txt);
						txt.reset();
					}

					if((line != nullptr && line->is_end_line) || width < 0) {
						cursor_.y += lh;
						cursor_.x = 0;
						width = eng.getWidthAtPosition(cursor_.y + eng.getOffset().y, containing.content_.width);
					}

					if(it != tnode->end()) {
						txt = std::make_shared<TextBox>(shared_from_this(), tnode);
					}
				}
			} else {
				// XXX fixme
				addChild(child);
			}
		}
	}

	void LineBox::handlePreChildLayout(LayoutEngine& eng, const Dimensions& containing)
	{
	}

	void LineBox::handleLayout(LayoutEngine& eng, const Dimensions& containing)
	{
		reflowChildren(eng, containing);

		// Our children should already be set at this point.
		// we want to compute our own width/height based on our children and set the
		// children's x/y
		FixedPoint height = 0;
		FixedPoint width = 0;

		// compute our width/height
		for(auto& child : getChildren()) {
			child->setContentX(width + starting_x_);

			height = std::max(height, child->getHeight() + child->getMBPHeight());
			width += child->getWidth() + getMBPWidth();
		}

		setContentWidth(width);
		setContentHeight(height);

		// computer&set children X/Y offsets
		for(auto& child : getChildren()) {
			FixedPoint child_y = 0;
			// XXX we should implement this fully.
			switch(child->getVerticalAlign()) {
				case css::CssVerticalAlign::BASELINE:
					// Align the baseline of the box with the baseline of the parent box.
					// If the box does not have a baseline, align the bottom margin edge
					// with the parent's baseline.
					child_y = child->getBaselineOffset();
					break;
				case css::CssVerticalAlign::MIDDLE:
					// Align the vertical midpoint of the box with the baseline of the
					// parent box plus half the x-height of the parent.
					child_y = height / 2;
					break;
				case css::CssVerticalAlign::BOTTOM:
					// Align the bottom of the aligned subtree with the bottom of the line box.
					child_y = child->getBottomOffset();
					break;
				case css::CssVerticalAlign::SUB:
					// Lower the baseline of the box to the proper position for subscripts of the
					// parent's box. (This value has no effect on the font size of the element's text.)
				case css::CssVerticalAlign::SUPER:
					// Raise the baseline of the box to the proper position for superscripts of the
					// parent's box. (This value has no effect on the font size of the element's text.)
				case css::CssVerticalAlign::TOP:
					// Align the top of the aligned subtree with the top of the line box.
				case css::CssVerticalAlign::TEXT_TOP:
					// Align the top of the box with the top of the parent's content area
				case css::CssVerticalAlign::TEXT_BOTTOM:
					// Align the bottom of the box with the bottom of the parent's content area
				case css::CssVerticalAlign::LENGTH:
				default:  break;
			}
			child->setContentY(child_y);
		}
	}

	void LineBox::handleRender(DisplayListPtr display_list, const point& offset) const
	{
		// do nothing
	}

	void LineBox::handleRenderBorder(DisplayListPtr display_list, const point& offset) const
	{
		// add a debug background, around content.
		/*rect r(getDimensions().content_.x + offset.x,
			getDimensions().content_.y + offset.y,
			getDimensions().content_.width,
			getDimensions().content_.height);
		auto sr = std::make_shared<SolidRenderable>(r, KRE::Color::colorSlateblue());
		display_list->addRenderable(sr);*/
	}
}
<commit_msg>Removed a couple of now erroneous statements.<commit_after>/*
	Copyright (C) 2003-2013 by Kristina Simpson <sweet.kristas@gmail.com>

	This software is provided 'as-is', without any express or implied
	warranty. In no event will the authors be held liable for any damages
	arising from the use of this software.

	Permission is granted to anyone to use this software for any purpose,
	including commercial applications, and to alter it and redistribute it
	freely, subject to the following restrictions:

	   1. The origin of this software must not be misrepresented; you must not
	   claim that you wrote the original software. If you use this software
	   in a product, an acknowledgment in the product documentation would be
	   appreciated but is not required.

	   2. Altered source versions must be plainly marked as such, and must not be
	   misrepresented as being the original software.

	   3. This notice may not be removed or altered from any source
	   distribution.
*/

#include "solid_renderable.hpp"
#include "xhtml_line_box.hpp"
#include "xhtml_layout_engine.hpp"
#include "xhtml_text_box.hpp"

namespace xhtml
{
	LineBox::LineBox(BoxPtr parent, const point& cursor)
		: Box(BoxId::LINE, parent, nullptr),
		  starting_x_(0),
		  cursor_(cursor)
	{
	}

	std::string LineBox::toString() const
	{
		std::ostringstream ss;
		ss << "LineBox: " << getDimensions().content_;
		return ss.str();
	}

	void LineBox::reflowChildren(LayoutEngine& eng, const Dimensions& containing)
	{
		FixedPoint lh = eng.getLineHeight();
		FixedPoint width = eng.getWidthAtPosition(cursor_.y + eng.getOffset().y, containing.content_.width) - cursor_.x;

		auto children = getChildren();
		clearChildren();
		for(auto& child : children) {
			if(child->id() == BoxId::TEXT) {
				auto txt = std::dynamic_pointer_cast<TextBox>(child);
				ASSERT_LOG(txt != nullptr, "Something went wrong child box with id TEXT couldn't be cast to Text box");
				TextPtr tnode = txt->getText();
				auto it = tnode->begin();

				while(it != tnode->end()) {
					it = txt->reflow(eng, cursor_, it);

					LinePtr line = txt->getLine();
					if(line != nullptr && !line->line.empty()) {
						txt->setContentX(cursor_.x);
						txt->setContentY(cursor_.y);

						FixedPoint x_inc = txt->getWidth() + txt->getMBPWidth();
						cursor_.x += x_inc;
						width -= x_inc;
						addChild(txt);
						txt.reset();
					}

					if((line != nullptr && line->is_end_line) || width < 0) {
						cursor_.y += lh;
						cursor_.x = 0;
						width = eng.getWidthAtPosition(cursor_.y + eng.getOffset().y, containing.content_.width);
					}

					if(it != tnode->end()) {
						txt = std::make_shared<TextBox>(shared_from_this(), tnode);
					}
				}
			} else {
				// XXX fixme
				addChild(child);
			}
		}
	}

	void LineBox::handlePreChildLayout(LayoutEngine& eng, const Dimensions& containing)
	{
	}

	void LineBox::handleLayout(LayoutEngine& eng, const Dimensions& containing)
	{
		reflowChildren(eng, containing);

		// Our children should already be set at this point.
		// we want to compute our own width/height based on our children and set the
		// children's x/y
		FixedPoint height = 0;
		FixedPoint width = 0;

		// compute our width/height
		for(auto& child : getChildren()) {
			//child->setContentX(width + starting_x_);

			height = std::max(height, child->getHeight() + child->getMBPHeight());
			width += child->getWidth() + getMBPWidth();
		}

		setContentWidth(width);
		setContentHeight(height);

		// computer&set children X/Y offsets
		for(auto& child : getChildren()) {
			FixedPoint child_y = 0;
			// XXX we should implement this fully.
			switch(child->getVerticalAlign()) {
				case css::CssVerticalAlign::BASELINE:
					// Align the baseline of the box with the baseline of the parent box.
					// If the box does not have a baseline, align the bottom margin edge
					// with the parent's baseline.
					child_y = child->getBaselineOffset();
					break;
				case css::CssVerticalAlign::MIDDLE:
					// Align the vertical midpoint of the box with the baseline of the
					// parent box plus half the x-height of the parent.
					child_y = height / 2;
					break;
				case css::CssVerticalAlign::BOTTOM:
					// Align the bottom of the aligned subtree with the bottom of the line box.
					child_y = child->getBottomOffset();
					break;
				case css::CssVerticalAlign::SUB:
					// Lower the baseline of the box to the proper position for subscripts of the
					// parent's box. (This value has no effect on the font size of the element's text.)
				case css::CssVerticalAlign::SUPER:
					// Raise the baseline of the box to the proper position for superscripts of the
					// parent's box. (This value has no effect on the font size of the element's text.)
				case css::CssVerticalAlign::TOP:
					// Align the top of the aligned subtree with the top of the line box.
				case css::CssVerticalAlign::TEXT_TOP:
					// Align the top of the box with the top of the parent's content area
				case css::CssVerticalAlign::TEXT_BOTTOM:
					// Align the bottom of the box with the bottom of the parent's content area
				case css::CssVerticalAlign::LENGTH:
				default:  break;
			}
			//child->setContentY(child_y);
		}
	}

	void LineBox::handleRender(DisplayListPtr display_list, const point& offset) const
	{
		// do nothing
	}

	void LineBox::handleRenderBorder(DisplayListPtr display_list, const point& offset) const
	{
		// add a debug background, around content.
		/*rect r(getDimensions().content_.x + offset.x,
			getDimensions().content_.y + offset.y,
			getDimensions().content_.width,
			getDimensions().content_.height);
		auto sr = std::make_shared<SolidRenderable>(r, KRE::Color::colorSlateblue());
		display_list->addRenderable(sr);*/
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2013 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Log.hpp>
#include <cstdlib>
#include <stdexcept>

#if defined(NAZARA_PLATFORM_WINDOWS)
	#include <windows.h>
#elif defined(NAZARA_PLATFORM_POSIX)
	#include <cstring>
#endif

#include <Nazara/Core/Debug.hpp>

void NzError::Error(nzErrorType type, const NzString& error)
{
	if ((s_flags & nzErrorFlag_Silent) == 0 || (s_flags & nzErrorFlag_SilentDisabled) != 0)
		NazaraLog->WriteError(type, error);

	s_lastError = error;
	s_lastErrorFile = "";
	s_lastErrorFunction = "";
	s_lastErrorLine = 0;

	#if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE
	if (type == nzErrorType_AssertFailed)
		std::exit(EXIT_FAILURE);
	#endif

	if ((s_flags & nzErrorFlag_ThrowException) != 0 && (s_flags & nzErrorFlag_ThrowExceptionDisabled) == 0)
		throw std::runtime_error(error);
}

void NzError::Error(nzErrorType type, const NzString& error, unsigned int line, const char* file, const char* function)
{
	if ((s_flags & nzErrorFlag_Silent) == 0 || (s_flags & nzErrorFlag_SilentDisabled) != 0)
		NazaraLog->WriteError(type, error, line, file, function);

	s_lastError = error;
	s_lastErrorFile = file;
	s_lastErrorFunction = function;
	s_lastErrorLine = line;

	#if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE
	if (type == nzErrorType_AssertFailed)
		std::exit(EXIT_FAILURE);
	#endif

	if ((s_flags & nzErrorFlag_ThrowException) != 0 && (s_flags & nzErrorFlag_ThrowExceptionDisabled) == 0)
		throw std::runtime_error(error);
}

nzUInt32 NzError::GetFlags()
{
	return s_flags;
}

NzString NzError::GetLastError(const char** file, unsigned int* line, const char** function)
{
	if (file)
		*file = s_lastErrorFile;

	if (line)
		*line = s_lastErrorLine;

	if (function)
		*function = s_lastErrorFunction;

	return s_lastError;
}

unsigned int NzError::GetLastSystemErrorCode()
{
	#if defined(NAZARA_PLATFORM_WINDOWS)
	return ::GetLastError();
	#elif defined(NAZARA_PLATFORM_POSIX)
	return errno;
	#else
		#error GetLastSystemErrorCode is not implemented on this platform
	return 0;
	#endif
}

NzString NzError::GetLastSystemError(unsigned int code)
{
	#if defined(NAZARA_PLATFORM_WINDOWS)
	wchar_t* buffer = nullptr;

	FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
				  nullptr,
				  code,
				  0,
				  reinterpret_cast<LPWSTR>(&buffer),
				  0,
				  nullptr);

	NzString error(NzString::Unicode(buffer));
	LocalFree(buffer);

	error.Trim(); // Pour une raison inconnue, Windows met deux-trois retours à la ligne après le message

	return error;
	#elif defined(NAZARA_PLATFORM_POSIX)
	return std::strerror(code);
	#else
		#error GetLastSystemError is not implemented on this platform

	return NzString("GetLastSystemError is not implemented on this platform");
	#endif
}

void NzError::SetFlags(nzUInt32 flags)
{
	s_flags = flags;
}

nzUInt32 NzError::s_flags = nzErrorFlag_None;
NzString NzError::s_lastError;
const char* NzError::s_lastErrorFunction = "";
const char* NzError::s_lastErrorFile = "";
unsigned int NzError::s_lastErrorLine = 0;
<commit_msg>Warnings no longer throw exceptions<commit_after>// Copyright (C) 2013 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Log.hpp>
#include <cstdlib>
#include <stdexcept>

#if defined(NAZARA_PLATFORM_WINDOWS)
	#include <windows.h>
#elif defined(NAZARA_PLATFORM_POSIX)
	#include <cstring>
#endif

#include <Nazara/Core/Debug.hpp>

void NzError::Error(nzErrorType type, const NzString& error)
{
	if ((s_flags & nzErrorFlag_Silent) == 0 || (s_flags & nzErrorFlag_SilentDisabled) != 0)
		NazaraLog->WriteError(type, error);

	s_lastError = error;
	s_lastErrorFile = "";
	s_lastErrorFunction = "";
	s_lastErrorLine = 0;

	#if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE
	if (type == nzErrorType_AssertFailed)
		std::exit(EXIT_FAILURE);
	#endif

	if (type != nzErrorType_Warning && (s_flags & nzErrorFlag_ThrowException) != 0 && (s_flags & nzErrorFlag_ThrowExceptionDisabled) == 0)
		throw std::runtime_error(error);
}

void NzError::Error(nzErrorType type, const NzString& error, unsigned int line, const char* file, const char* function)
{
	if ((s_flags & nzErrorFlag_Silent) == 0 || (s_flags & nzErrorFlag_SilentDisabled) != 0)
		NazaraLog->WriteError(type, error, line, file, function);

	s_lastError = error;
	s_lastErrorFile = file;
	s_lastErrorFunction = function;
	s_lastErrorLine = line;

	#if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE
	if (type == nzErrorType_AssertFailed)
		std::exit(EXIT_FAILURE);
	#endif

	if (type != nzErrorType_Warning && (s_flags & nzErrorFlag_ThrowException) != 0 && (s_flags & nzErrorFlag_ThrowExceptionDisabled) == 0)
		throw std::runtime_error(error);
}

nzUInt32 NzError::GetFlags()
{
	return s_flags;
}

NzString NzError::GetLastError(const char** file, unsigned int* line, const char** function)
{
	if (file)
		*file = s_lastErrorFile;

	if (line)
		*line = s_lastErrorLine;

	if (function)
		*function = s_lastErrorFunction;

	return s_lastError;
}

unsigned int NzError::GetLastSystemErrorCode()
{
	#if defined(NAZARA_PLATFORM_WINDOWS)
	return ::GetLastError();
	#elif defined(NAZARA_PLATFORM_POSIX)
	return errno;
	#else
		#error GetLastSystemErrorCode is not implemented on this platform
	return 0;
	#endif
}

NzString NzError::GetLastSystemError(unsigned int code)
{
	#if defined(NAZARA_PLATFORM_WINDOWS)
	wchar_t* buffer = nullptr;

	FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
				  nullptr,
				  code,
				  0,
				  reinterpret_cast<LPWSTR>(&buffer),
				  0,
				  nullptr);

	NzString error(NzString::Unicode(buffer));
	LocalFree(buffer);

	error.Trim(); // Pour une raison inconnue, Windows met deux-trois retours à la ligne après le message

	return error;
	#elif defined(NAZARA_PLATFORM_POSIX)
	return std::strerror(code);
	#else
		#error GetLastSystemError is not implemented on this platform

	return NzString("GetLastSystemError is not implemented on this platform");
	#endif
}

void NzError::SetFlags(nzUInt32 flags)
{
	s_flags = flags;
}

nzUInt32 NzError::s_flags = nzErrorFlag_None;
NzString NzError::s_lastError;
const char* NzError::s_lastErrorFunction = "";
const char* NzError::s_lastErrorFile = "";
unsigned int NzError::s_lastErrorLine = 0;
<|endoftext|>