<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (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 qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "pvreglscreen.h"
#include "pvreglwindowsurface.h"
#include "pvrqwsdrawable_p.h"
#include <QRegExp>
#include <qwindowsystem_qws.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/kd.h>
#include <fcntl.h>
#include <unistd.h>

PvrEglScreen::PvrEglScreen(int displayId)
    : QGLScreen(displayId)
{
    setOptions(NativeWindows);
    setSupportsBlitInClients(true);
    setSurfaceFunctions(new PvrEglScreenSurfaceFunctions(this, displayId));
    fd = -1;
    ttyfd = -1;
    doGraphicsMode = true;
    oldKdMode = KD_TEXT;
    if (QWSServer::instance())
        holder = new PvrEglSurfaceHolder();
    else
        holder = 0;
}

PvrEglScreen::~PvrEglScreen()
{
    if (fd >= 0)
        ::close(fd);
    delete holder;
}

bool PvrEglScreen::initDevice()
{
    openTty();
    return true;
}

bool PvrEglScreen::connect(const QString &displaySpec)
{
    if (!pvrQwsDisplayOpen())
        return false;

    // Initialize the QScreen properties.
    data = (uchar *)(pvrQwsDisplay.screens[0].mapped);
    w = pvrQwsDisplay.screens[0].screenRect.width;
    h = pvrQwsDisplay.screens[0].screenRect.height;
    lstep = pvrQwsDisplay.screens[0].screenStride;
    dw = w;
    dh = h;
    size = h * lstep;
    mapsize = size;
    switch (pvrQwsDisplay.screens[0].pixelFormat) {
	case PVR2D_RGB565:
            d = 16;
            setPixelFormat(QImage::Format_RGB16);
            break;
	case PVR2D_ARGB4444:
            d = 16;
            setPixelFormat(QImage::Format_ARGB4444_Premultiplied);
            break;
	case PVR2D_ARGB8888:
            d = 32;
            setPixelFormat(QImage::Format_ARGB32);
            break;
        default:
            pvrQwsDisplayClose();
            qWarning("PvrEglScreen::connect: unsupported pixel format %d", (int)(pvrQwsDisplay.screens[0].pixelFormat));
            return false;
    }

    // Handle display physical size spec.
    QStringList displayArgs = displaySpec.split(QLatin1Char(':'));
    QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)"));
    int dimIdxW = displayArgs.indexOf(mmWidthRx);
    QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)"));
    int dimIdxH = displayArgs.indexOf(mmHeightRx);
    if (dimIdxW >= 0) {
        mmWidthRx.exactMatch(displayArgs.at(dimIdxW));
        physWidth = mmWidthRx.cap(1).toInt();
        if (dimIdxH < 0)
            physHeight = dh*physWidth/dw;
    }
    if (dimIdxH >= 0) {
        mmHeightRx.exactMatch(displayArgs.at(dimIdxH));
        physHeight = mmHeightRx.cap(1).toInt();
        if (dimIdxW < 0)
            physWidth = dw*physHeight/dh;
    }
    if (dimIdxW < 0 && dimIdxH < 0) {
        const int dpi = 72;
        physWidth = qRound(dw * 25.4 / dpi);
        physHeight = qRound(dh * 25.4 / dpi);
    }

    // Find the name of the tty device to use.
    QRegExp ttyRegExp(QLatin1String("tty=(.*)"));
    if (displayArgs.indexOf(ttyRegExp) != -1)
        ttyDevice = ttyRegExp.cap(1);
    if (displayArgs.contains(QLatin1String("nographicsmodeswitch")))
        doGraphicsMode = false;

    // The screen is ready.
    return true;
}

void PvrEglScreen::disconnect()
{
    pvrQwsDisplayClose();
}

void PvrEglScreen::shutdownDevice()
{
    closeTty();
}

void PvrEglScreen::blit(const QImage &img, const QPoint &topLeft, const QRegion &region)
{
    QGLScreen::blit(img, topLeft, region);
    sync();
}

void PvrEglScreen::solidFill(const QColor &color, const QRegion &region)
{
    QGLScreen::solidFill(color, region);
    sync();
}

bool PvrEglScreen::chooseContext
    (QGLContext *context, const QGLContext *shareContext)
{
    // We use PvrEglScreenSurfaceFunctions instead.
    Q_UNUSED(context);
    Q_UNUSED(shareContext);
    return false;
}

bool PvrEglScreen::hasOpenGL()
{
    return true;
}

QWSWindowSurface* PvrEglScreen::createSurface(QWidget *widget) const
{
    if (qobject_cast<QGLWidget*>(widget))
        return new PvrEglWindowSurface(widget, (QScreen *)this, displayId);

    return QScreen::createSurface(widget);
}

QWSWindowSurface* PvrEglScreen::createSurface(const QString &key) const
{
    if (key == QLatin1String("PvrEgl"))
        return new PvrEglWindowSurface(holder);

    return QScreen::createSurface(key);
}

void PvrEglScreen::sync()
{
    // Put code here to synchronize 2D and 3D operations if necessary.
}

void PvrEglScreen::openTty()
{
    const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0};

    if (ttyDevice.isEmpty()) {
        for (const char * const *dev = devs; *dev; ++dev) {
            ttyfd = ::open(*dev, O_RDWR);
            if (ttyfd != -1)
                break;
        }
    } else {
        ttyfd = ::open(ttyDevice.toAscii().constData(), O_RDWR);
    }

    if (ttyfd == -1)
        return;

    ::fcntl(ttyfd, F_SETFD, FD_CLOEXEC);

    if (doGraphicsMode) {
        ioctl(ttyfd, KDGETMODE, &oldKdMode);
        if (oldKdMode != KD_GRAPHICS) {
            int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS);
            if (ret == -1)
                doGraphicsMode = false;
        }
    }

    // No blankin' screen, no blinkin' cursor!, no cursor!
    const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c";
    ::write(ttyfd, termctl, sizeof(termctl));
}

void PvrEglScreen::closeTty()
{
    if (ttyfd == -1)
        return;

    if (doGraphicsMode)
        ioctl(ttyfd, KDSETMODE, oldKdMode);

    // Blankin' screen, blinkin' cursor!
    const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c";
    ::write(ttyfd, termctl, sizeof(termctl));

    ::close(ttyfd);
    ttyfd = -1;
}

bool PvrEglScreenSurfaceFunctions::createNativeWindow(QWidget *widget, EGLNativeWindowType *native)
{
    QWSWindowSurface *surface =
        static_cast<QWSWindowSurface *>(widget->windowSurface());
    if (!surface) {
        // The widget does not have a surface yet, so give it one.
        surface = new PvrEglWindowSurface(widget, screen, displayId);
        widget->setWindowSurface(surface);
    } else if (surface->key() != QLatin1String("PvrEgl")) {
        // The application has attached a QGLContext to an ordinary QWidget.
        // Replace the widget's window surface with a new one that can do GL.
        QRect geometry = widget->frameGeometry();
        geometry.moveTo(widget->mapToGlobal(QPoint(0, 0)));
        surface = new PvrEglWindowSurface(widget, screen, displayId);
        surface->setGeometry(geometry);
        widget->setWindowSurface(surface);
        widget->setAttribute(Qt::WA_NoSystemBackground, true);
    }
    PvrEglWindowSurface *nsurface = static_cast<PvrEglWindowSurface*>(surface);
    *native = (EGLNativeWindowType)(nsurface->nativeDrawable());
    return true;
}

// The PowerVR engine on the device needs to allocate about 2Mb of
// contiguous physical memory to manage drawing into a surface.
//
// The problem is that once Qtopia begins its startup sequence,
// it allocates enough memory to severely fragment the physical
// address space on the device.  This leaves the PowerVR engine
// unable to allocate the necessary contiguous physical memory
// when an EGL surface is created.
//
// A solution to this is to pre-allocate a dummy surface early
// in the startup sequence before memory becomes fragmented,
// reserving it for any future EGL applications to use.
//
// However, the PowerVR engine has problems managing multiple
// surfaces concurrently, and so real EGL applications end up
// with unacceptably slow frame rates unless the dummy surface
// is destroyed while the real EGL applications are running.
//
// In summary, we need to try to ensure that there is always at
// least one EGL surface active at any given time to reserve the
// memory but destroy the temporary surface when a real surface
// is using the device.  That is the purpose of PvrEglSurfaceHolder.

PvrEglSurfaceHolder::PvrEglSurfaceHolder(QObject *parent)
    : QObject(parent)
{
    numRealSurfaces = 0;

    PvrQwsRect rect;
    rect.x = 0;
    rect.y = 0;
    rect.width = 16;
    rect.height = 16;
    tempSurface = pvrQwsCreateWindow(0, -1, &rect);

    dpy = EGL_NO_DISPLAY;
    config = 0;
    surface = EGL_NO_SURFACE;

    dpy = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
    if (!eglInitialize(dpy, 0, 0)) {
        qWarning("Could not initialize EGL display - are the drivers loaded?");
        dpy = EGL_NO_DISPLAY;
        return;
    }

    EGLint attribList[16];
    int temp = 0;
    attribList[temp++] = EGL_LEVEL;     // Framebuffer level 0
    attribList[temp++] = 0;
    attribList[temp++] = EGL_SURFACE_TYPE;
    attribList[temp++] = EGL_WINDOW_BIT;
    attribList[temp++] = EGL_NONE;

    EGLint numConfigs = 0;
    if (!eglChooseConfig(dpy, attribList, &config, 1, &numConfigs) || numConfigs != 1) {
        qWarning("Could not find a matching a EGL configuration");
        eglTerminate(dpy);
        dpy = EGL_NO_DISPLAY;
        return;
    }

    surface = eglCreateWindowSurface
        (dpy, config, (EGLNativeWindowType)(-1), NULL);
    if (surface == EGL_NO_SURFACE)
        qWarning("Could not create the temporary EGL surface");
}

PvrEglSurfaceHolder::~PvrEglSurfaceHolder()
{
    if (surface != EGL_NO_SURFACE)
        eglDestroySurface(dpy, surface);
    if (dpy != EGL_NO_DISPLAY)
        eglTerminate(dpy);
    if (tempSurface)
        pvrQwsDestroyDrawable(tempSurface);
}

// Add a real EGL surface to the system.
void PvrEglSurfaceHolder::addSurface()
{
    ++numRealSurfaces;
    if (numRealSurfaces == 1) {
        // Destroy the temporary surface while some other application
        // is making use of the EGL sub-system for 3D rendering.
        if (surface != EGL_NO_SURFACE) {
            eglDestroySurface(dpy, surface);
            surface = EGL_NO_SURFACE;
        }
    }
}

// Remove an actual EGL surface from the system.
void PvrEglSurfaceHolder::removeSurface()
{
    if (numRealSurfaces > 0) {
        --numRealSurfaces;
        if (numRealSurfaces == 0) {
            // The last real EGL surface has been destroyed, so re-create
            // the temporary surface.  There is a race condition here in
            // that Qtopia could allocate a lot of memory just after
            // the real EGL surface is destroyed but before we could
            // create the temporary surface again.
            if (surface == EGL_NO_SURFACE && dpy != EGL_NO_DISPLAY) {
                surface = eglCreateWindowSurface
                    (dpy, config, (EGLNativeWindowType)(-1), NULL);
                if (surface == EGL_NO_SURFACE)
                    qWarning("Could not re-create the temporary EGL surface");
            }
        }
    }
}
<commit_msg>Make sure we use a premultiplied alpha format for 32 bit EGL screens.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (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 qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "pvreglscreen.h"
#include "pvreglwindowsurface.h"
#include "pvrqwsdrawable_p.h"
#include <QRegExp>
#include <qwindowsystem_qws.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/kd.h>
#include <fcntl.h>
#include <unistd.h>

PvrEglScreen::PvrEglScreen(int displayId)
    : QGLScreen(displayId)
{
    setOptions(NativeWindows);
    setSupportsBlitInClients(true);
    setSurfaceFunctions(new PvrEglScreenSurfaceFunctions(this, displayId));
    fd = -1;
    ttyfd = -1;
    doGraphicsMode = true;
    oldKdMode = KD_TEXT;
    if (QWSServer::instance())
        holder = new PvrEglSurfaceHolder();
    else
        holder = 0;
}

PvrEglScreen::~PvrEglScreen()
{
    if (fd >= 0)
        ::close(fd);
    delete holder;
}

bool PvrEglScreen::initDevice()
{
    openTty();
    return true;
}

bool PvrEglScreen::connect(const QString &displaySpec)
{
    if (!pvrQwsDisplayOpen())
        return false;

    // Initialize the QScreen properties.
    data = (uchar *)(pvrQwsDisplay.screens[0].mapped);
    w = pvrQwsDisplay.screens[0].screenRect.width;
    h = pvrQwsDisplay.screens[0].screenRect.height;
    lstep = pvrQwsDisplay.screens[0].screenStride;
    dw = w;
    dh = h;
    size = h * lstep;
    mapsize = size;
    switch (pvrQwsDisplay.screens[0].pixelFormat) {
	case PVR2D_RGB565:
            d = 16;
            setPixelFormat(QImage::Format_RGB16);
            break;
	case PVR2D_ARGB4444:
            d = 16;
            setPixelFormat(QImage::Format_ARGB4444_Premultiplied);
            break;
	case PVR2D_ARGB8888:
            d = 32;
            setPixelFormat(QImage::Format_ARGB32_Premultiplied);
            break;
        default:
            pvrQwsDisplayClose();
            qWarning("PvrEglScreen::connect: unsupported pixel format %d", (int)(pvrQwsDisplay.screens[0].pixelFormat));
            return false;
    }

    // Handle display physical size spec.
    QStringList displayArgs = displaySpec.split(QLatin1Char(':'));
    QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)"));
    int dimIdxW = displayArgs.indexOf(mmWidthRx);
    QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)"));
    int dimIdxH = displayArgs.indexOf(mmHeightRx);
    if (dimIdxW >= 0) {
        mmWidthRx.exactMatch(displayArgs.at(dimIdxW));
        physWidth = mmWidthRx.cap(1).toInt();
        if (dimIdxH < 0)
            physHeight = dh*physWidth/dw;
    }
    if (dimIdxH >= 0) {
        mmHeightRx.exactMatch(displayArgs.at(dimIdxH));
        physHeight = mmHeightRx.cap(1).toInt();
        if (dimIdxW < 0)
            physWidth = dw*physHeight/dh;
    }
    if (dimIdxW < 0 && dimIdxH < 0) {
        const int dpi = 72;
        physWidth = qRound(dw * 25.4 / dpi);
        physHeight = qRound(dh * 25.4 / dpi);
    }

    // Find the name of the tty device to use.
    QRegExp ttyRegExp(QLatin1String("tty=(.*)"));
    if (displayArgs.indexOf(ttyRegExp) != -1)
        ttyDevice = ttyRegExp.cap(1);
    if (displayArgs.contains(QLatin1String("nographicsmodeswitch")))
        doGraphicsMode = false;

    // The screen is ready.
    return true;
}

void PvrEglScreen::disconnect()
{
    pvrQwsDisplayClose();
}

void PvrEglScreen::shutdownDevice()
{
    closeTty();
}

void PvrEglScreen::blit(const QImage &img, const QPoint &topLeft, const QRegion &region)
{
    QGLScreen::blit(img, topLeft, region);
    sync();
}

void PvrEglScreen::solidFill(const QColor &color, const QRegion &region)
{
    QGLScreen::solidFill(color, region);
    sync();
}

bool PvrEglScreen::chooseContext
    (QGLContext *context, const QGLContext *shareContext)
{
    // We use PvrEglScreenSurfaceFunctions instead.
    Q_UNUSED(context);
    Q_UNUSED(shareContext);
    return false;
}

bool PvrEglScreen::hasOpenGL()
{
    return true;
}

QWSWindowSurface* PvrEglScreen::createSurface(QWidget *widget) const
{
    if (qobject_cast<QGLWidget*>(widget))
        return new PvrEglWindowSurface(widget, (QScreen *)this, displayId);

    return QScreen::createSurface(widget);
}

QWSWindowSurface* PvrEglScreen::createSurface(const QString &key) const
{
    if (key == QLatin1String("PvrEgl"))
        return new PvrEglWindowSurface(holder);

    return QScreen::createSurface(key);
}

void PvrEglScreen::sync()
{
    // Put code here to synchronize 2D and 3D operations if necessary.
}

void PvrEglScreen::openTty()
{
    const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0};

    if (ttyDevice.isEmpty()) {
        for (const char * const *dev = devs; *dev; ++dev) {
            ttyfd = ::open(*dev, O_RDWR);
            if (ttyfd != -1)
                break;
        }
    } else {
        ttyfd = ::open(ttyDevice.toAscii().constData(), O_RDWR);
    }

    if (ttyfd == -1)
        return;

    ::fcntl(ttyfd, F_SETFD, FD_CLOEXEC);

    if (doGraphicsMode) {
        ioctl(ttyfd, KDGETMODE, &oldKdMode);
        if (oldKdMode != KD_GRAPHICS) {
            int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS);
            if (ret == -1)
                doGraphicsMode = false;
        }
    }

    // No blankin' screen, no blinkin' cursor!, no cursor!
    const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c";
    ::write(ttyfd, termctl, sizeof(termctl));
}

void PvrEglScreen::closeTty()
{
    if (ttyfd == -1)
        return;

    if (doGraphicsMode)
        ioctl(ttyfd, KDSETMODE, oldKdMode);

    // Blankin' screen, blinkin' cursor!
    const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c";
    ::write(ttyfd, termctl, sizeof(termctl));

    ::close(ttyfd);
    ttyfd = -1;
}

bool PvrEglScreenSurfaceFunctions::createNativeWindow(QWidget *widget, EGLNativeWindowType *native)
{
    QWSWindowSurface *surface =
        static_cast<QWSWindowSurface *>(widget->windowSurface());
    if (!surface) {
        // The widget does not have a surface yet, so give it one.
        surface = new PvrEglWindowSurface(widget, screen, displayId);
        widget->setWindowSurface(surface);
    } else if (surface->key() != QLatin1String("PvrEgl")) {
        // The application has attached a QGLContext to an ordinary QWidget.
        // Replace the widget's window surface with a new one that can do GL.
        QRect geometry = widget->frameGeometry();
        geometry.moveTo(widget->mapToGlobal(QPoint(0, 0)));
        surface = new PvrEglWindowSurface(widget, screen, displayId);
        surface->setGeometry(geometry);
        widget->setWindowSurface(surface);
        widget->setAttribute(Qt::WA_NoSystemBackground, true);
    }
    PvrEglWindowSurface *nsurface = static_cast<PvrEglWindowSurface*>(surface);
    *native = (EGLNativeWindowType)(nsurface->nativeDrawable());
    return true;
}

// The PowerVR engine on the device needs to allocate about 2Mb of
// contiguous physical memory to manage drawing into a surface.
//
// The problem is that once Qtopia begins its startup sequence,
// it allocates enough memory to severely fragment the physical
// address space on the device.  This leaves the PowerVR engine
// unable to allocate the necessary contiguous physical memory
// when an EGL surface is created.
//
// A solution to this is to pre-allocate a dummy surface early
// in the startup sequence before memory becomes fragmented,
// reserving it for any future EGL applications to use.
//
// However, the PowerVR engine has problems managing multiple
// surfaces concurrently, and so real EGL applications end up
// with unacceptably slow frame rates unless the dummy surface
// is destroyed while the real EGL applications are running.
//
// In summary, we need to try to ensure that there is always at
// least one EGL surface active at any given time to reserve the
// memory but destroy the temporary surface when a real surface
// is using the device.  That is the purpose of PvrEglSurfaceHolder.

PvrEglSurfaceHolder::PvrEglSurfaceHolder(QObject *parent)
    : QObject(parent)
{
    numRealSurfaces = 0;

    PvrQwsRect rect;
    rect.x = 0;
    rect.y = 0;
    rect.width = 16;
    rect.height = 16;
    tempSurface = pvrQwsCreateWindow(0, -1, &rect);

    dpy = EGL_NO_DISPLAY;
    config = 0;
    surface = EGL_NO_SURFACE;

    dpy = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
    if (!eglInitialize(dpy, 0, 0)) {
        qWarning("Could not initialize EGL display - are the drivers loaded?");
        dpy = EGL_NO_DISPLAY;
        return;
    }

    EGLint attribList[16];
    int temp = 0;
    attribList[temp++] = EGL_LEVEL;     // Framebuffer level 0
    attribList[temp++] = 0;
    attribList[temp++] = EGL_SURFACE_TYPE;
    attribList[temp++] = EGL_WINDOW_BIT;
    attribList[temp++] = EGL_NONE;

    EGLint numConfigs = 0;
    if (!eglChooseConfig(dpy, attribList, &config, 1, &numConfigs) || numConfigs != 1) {
        qWarning("Could not find a matching a EGL configuration");
        eglTerminate(dpy);
        dpy = EGL_NO_DISPLAY;
        return;
    }

    surface = eglCreateWindowSurface
        (dpy, config, (EGLNativeWindowType)(-1), NULL);
    if (surface == EGL_NO_SURFACE)
        qWarning("Could not create the temporary EGL surface");
}

PvrEglSurfaceHolder::~PvrEglSurfaceHolder()
{
    if (surface != EGL_NO_SURFACE)
        eglDestroySurface(dpy, surface);
    if (dpy != EGL_NO_DISPLAY)
        eglTerminate(dpy);
    if (tempSurface)
        pvrQwsDestroyDrawable(tempSurface);
}

// Add a real EGL surface to the system.
void PvrEglSurfaceHolder::addSurface()
{
    ++numRealSurfaces;
    if (numRealSurfaces == 1) {
        // Destroy the temporary surface while some other application
        // is making use of the EGL sub-system for 3D rendering.
        if (surface != EGL_NO_SURFACE) {
            eglDestroySurface(dpy, surface);
            surface = EGL_NO_SURFACE;
        }
    }
}

// Remove an actual EGL surface from the system.
void PvrEglSurfaceHolder::removeSurface()
{
    if (numRealSurfaces > 0) {
        --numRealSurfaces;
        if (numRealSurfaces == 0) {
            // The last real EGL surface has been destroyed, so re-create
            // the temporary surface.  There is a race condition here in
            // that Qtopia could allocate a lot of memory just after
            // the real EGL surface is destroyed but before we could
            // create the temporary surface again.
            if (surface == EGL_NO_SURFACE && dpy != EGL_NO_DISPLAY) {
                surface = eglCreateWindowSurface
                    (dpy, config, (EGLNativeWindowType)(-1), NULL);
                if (surface == EGL_NO_SURFACE)
                    qWarning("Could not re-create the temporary EGL surface");
            }
        }
    }
}
<|endoftext|>


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

#include "chrome/browser/ui/webui/extensions/extension_error_ui_util.h"

#include <string>

#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/values.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_error.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/file_highlighter.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"

namespace extensions {
namespace error_ui_util {

namespace {

// Keys for objects passed to and from extension error UI.
const char kPathSuffixKey[] = "pathSuffix";
const char kTitleKey[] = "title";

std::string ReadFileToString(const base::FilePath& path) {
  std::string data;
  base::ReadFileToString(path, &data);
  return data;
}

void GetManifestFileCallback(base::DictionaryValue* results,
                             const std::string& key,
                             const std::string& specific,
                             const RequestFileSourceCallback& response,
                             const std::string& contents) {
  ManifestHighlighter highlighter(contents, key, specific);
  highlighter.SetHighlightedRegions(results);
  response.Run(*results);
}

void GetSourceFileCallback(base::DictionaryValue* results,
                           int line_number,
                           const RequestFileSourceCallback& response,
                           const std::string& contents) {
  SourceHighlighter highlighter(contents, line_number);
  highlighter.SetHighlightedRegions(results);
  response.Run(*results);
}

}  // namespace

void HandleRequestFileSource(const base::DictionaryValue* args,
                             Profile* profile,
                             const RequestFileSourceCallback& response) {
  // Three required arguments: extension_id, path_suffix, and error_message.
  std::string extension_id;
  base::FilePath::StringType path_suffix_string;
  base::string16 error_message;

  if (!args->GetString(kPathSuffixKey, &path_suffix_string) ||
      !args->GetString(ExtensionError::kExtensionIdKey, &extension_id) ||
      !args->GetString(ExtensionError::kMessageKey, &error_message)) {
    NOTREACHED();
    return;
  }

  ExtensionService* extension_service =
      ExtensionSystem::Get(profile)->extension_service();
  if (!extension_service)
    return;

  const Extension* extension = extension_service->GetExtensionById(
      extension_id, true /* include disabled */);

  // Under no circumstances should we ever need to reference a file outside of
  // the extension's directory. If it tries to, abort.
  base::FilePath path_suffix(path_suffix_string);
  if (path_suffix.ReferencesParent())
    return;

  base::FilePath path = extension->path().Append(path_suffix);

  // Setting the title and the error message is the same for all file types.
  scoped_ptr<base::DictionaryValue> results(new base::DictionaryValue);
  results->SetString(kTitleKey,
                     base::UTF8ToUTF16(extension->name()) +
                         base::ASCIIToUTF16(": ") +
                         path.BaseName().LossyDisplayName());
  results->SetString(ExtensionError::kMessageKey, error_message);

  base::Callback<void(const std::string&)> reply;
  if (path_suffix_string == kManifestFilename) {
    std::string manifest_key;
    if (!args->GetString(ManifestError::kManifestKeyKey, &manifest_key)) {
      NOTREACHED();
      return;
    }

    // A "specific" location is optional.
    std::string specific;
    args->GetString(ManifestError::kManifestSpecificKey, &specific);

    reply = base::Bind(&GetManifestFileCallback,
                       base::Owned(results.release()),
                       manifest_key,
                       specific,
                       response);
  } else {
    int line_number = 0;
    args->GetInteger(RuntimeError::kLineNumberKey, &line_number);

    reply = base::Bind(&GetSourceFileCallback,
                       base::Owned(results.release()),
                       line_number,
                       response);
  }

  base::PostTaskAndReplyWithResult(content::BrowserThread::GetBlockingPool(),
                                   FROM_HERE,
                                   base::Bind(&ReadFileToString, path),
                                   reply);
}

void HandleOpenDevTools(const base::DictionaryValue* args) {
  int render_process_id = 0;
  int render_view_id = 0;

  // The render view and render process ids are required.
  if (!args->GetInteger(RuntimeError::kRenderProcessIdKey,
                        &render_process_id) ||
      !args->GetInteger(RuntimeError::kRenderViewIdKey, &render_view_id)) {
    NOTREACHED();
    return;
  }

  content::RenderViewHost* rvh =
      content::RenderViewHost::FromID(render_process_id, render_view_id);

  // It's possible that the render view was closed since we last updated the
  // links. Handle this gracefully.
  if (!rvh)
    return;

  // If we include a url, we should inspect it specifically (and not just the
  // render view).
  base::string16 url;
  if (args->GetString(RuntimeError::kUrlKey, &url)) {
    // Line and column numbers are optional; default to the first line.
    int line_number = 1;
    int column_number = 1;
    args->GetInteger(RuntimeError::kLineNumberKey, &line_number);
    args->GetInteger(RuntimeError::kColumnNumberKey, &column_number);

    // Line/column numbers are reported in display-friendly 1-based numbers,
    // but are inspected in zero-based numbers.
    DevToolsWindow::OpenDevToolsWindow(
        rvh,
        DevToolsToggleAction::Reveal(url, line_number - 1, column_number - 1));
  } else {
    DevToolsWindow::OpenDevToolsWindow(rvh);
  }

  // Once we open the inspector, we focus on the appropriate tab...
  content::WebContents* web_contents =
      content::WebContents::FromRenderViewHost(rvh);
  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);

  // ... but some pages (popups and apps) don't have tabs, and some (background
  // pages) don't have an associated browser. For these, the inspector opens in
  // a new window, and our work is done.
  if (!browser || !browser->is_type_tabbed())
    return;

  TabStripModel* tab_strip = browser->tab_strip_model();
  tab_strip->ActivateTabAt(tab_strip->GetIndexOfWebContents(web_contents),
                           false);  // Not through direct user gesture.
}

}  // namespace error_ui_util
}  // namespace extensions
<commit_msg>Check Extension in extension_error_ui_util. BUG=361082<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/extensions/extension_error_ui_util.h"

#include <string>

#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/values.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_error.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/file_highlighter.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"

namespace extensions {
namespace error_ui_util {

namespace {

// Keys for objects passed to and from extension error UI.
const char kPathSuffixKey[] = "pathSuffix";
const char kTitleKey[] = "title";

std::string ReadFileToString(const base::FilePath& path) {
  std::string data;
  base::ReadFileToString(path, &data);
  return data;
}

void GetManifestFileCallback(base::DictionaryValue* results,
                             const std::string& key,
                             const std::string& specific,
                             const RequestFileSourceCallback& response,
                             const std::string& contents) {
  ManifestHighlighter highlighter(contents, key, specific);
  highlighter.SetHighlightedRegions(results);
  response.Run(*results);
}

void GetSourceFileCallback(base::DictionaryValue* results,
                           int line_number,
                           const RequestFileSourceCallback& response,
                           const std::string& contents) {
  SourceHighlighter highlighter(contents, line_number);
  highlighter.SetHighlightedRegions(results);
  response.Run(*results);
}

}  // namespace

void HandleRequestFileSource(const base::DictionaryValue* args,
                             Profile* profile,
                             const RequestFileSourceCallback& response) {
  // Three required arguments: extension_id, path_suffix, and error_message.
  std::string extension_id;
  base::FilePath::StringType path_suffix_string;
  base::string16 error_message;

  if (!args->GetString(kPathSuffixKey, &path_suffix_string) ||
      !args->GetString(ExtensionError::kExtensionIdKey, &extension_id) ||
      !args->GetString(ExtensionError::kMessageKey, &error_message)) {
    NOTREACHED();
    return;
  }

  const Extension* extension =
      ExtensionRegistry::Get(profile)->GetExtensionById(
          extension_id, ExtensionRegistry::EVERYTHING);

  if (!extension) {
    NOTREACHED();
    return;
  }

  // Under no circumstances should we ever need to reference a file outside of
  // the extension's directory. If it tries to, abort.
  base::FilePath path_suffix(path_suffix_string);
  if (path_suffix.ReferencesParent())
    return;

  base::FilePath path = extension->path().Append(path_suffix);

  // Setting the title and the error message is the same for all file types.
  scoped_ptr<base::DictionaryValue> results(new base::DictionaryValue);
  results->SetString(kTitleKey,
                     base::UTF8ToUTF16(extension->name()) +
                         base::ASCIIToUTF16(": ") +
                         path.BaseName().LossyDisplayName());
  results->SetString(ExtensionError::kMessageKey, error_message);

  base::Callback<void(const std::string&)> reply;
  if (path_suffix_string == kManifestFilename) {
    std::string manifest_key;
    if (!args->GetString(ManifestError::kManifestKeyKey, &manifest_key)) {
      NOTREACHED();
      return;
    }

    // A "specific" location is optional.
    std::string specific;
    args->GetString(ManifestError::kManifestSpecificKey, &specific);

    reply = base::Bind(&GetManifestFileCallback,
                       base::Owned(results.release()),
                       manifest_key,
                       specific,
                       response);
  } else {
    int line_number = 0;
    args->GetInteger(RuntimeError::kLineNumberKey, &line_number);

    reply = base::Bind(&GetSourceFileCallback,
                       base::Owned(results.release()),
                       line_number,
                       response);
  }

  base::PostTaskAndReplyWithResult(content::BrowserThread::GetBlockingPool(),
                                   FROM_HERE,
                                   base::Bind(&ReadFileToString, path),
                                   reply);
}

void HandleOpenDevTools(const base::DictionaryValue* args) {
  int render_process_id = 0;
  int render_view_id = 0;

  // The render view and render process ids are required.
  if (!args->GetInteger(RuntimeError::kRenderProcessIdKey,
                        &render_process_id) ||
      !args->GetInteger(RuntimeError::kRenderViewIdKey, &render_view_id)) {
    NOTREACHED();
    return;
  }

  content::RenderViewHost* rvh =
      content::RenderViewHost::FromID(render_process_id, render_view_id);

  // It's possible that the render view was closed since we last updated the
  // links. Handle this gracefully.
  if (!rvh)
    return;

  // If we include a url, we should inspect it specifically (and not just the
  // render view).
  base::string16 url;
  if (args->GetString(RuntimeError::kUrlKey, &url)) {
    // Line and column numbers are optional; default to the first line.
    int line_number = 1;
    int column_number = 1;
    args->GetInteger(RuntimeError::kLineNumberKey, &line_number);
    args->GetInteger(RuntimeError::kColumnNumberKey, &column_number);

    // Line/column numbers are reported in display-friendly 1-based numbers,
    // but are inspected in zero-based numbers.
    DevToolsWindow::OpenDevToolsWindow(
        rvh,
        DevToolsToggleAction::Reveal(url, line_number - 1, column_number - 1));
  } else {
    DevToolsWindow::OpenDevToolsWindow(rvh);
  }

  // Once we open the inspector, we focus on the appropriate tab...
  content::WebContents* web_contents =
      content::WebContents::FromRenderViewHost(rvh);
  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);

  // ... but some pages (popups and apps) don't have tabs, and some (background
  // pages) don't have an associated browser. For these, the inspector opens in
  // a new window, and our work is done.
  if (!browser || !browser->is_type_tabbed())
    return;

  TabStripModel* tab_strip = browser->tab_strip_model();
  tab_strip->ActivateTabAt(tab_strip->GetIndexOfWebContents(web_contents),
                           false);  // Not through direct user gesture.
}

}  // namespace error_ui_util
}  // namespace extensions
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <xpathapi.hxx>

#include <stdarg.h>
#include <string.h>

#include <libxml/tree.h>
#include <libxml/xmlerror.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>

#include <rtl/ustrbuf.hxx>

#include <nodelist.hxx>
#include <xpathobject.hxx>

#include "../dom/node.hxx"
#include "../dom/document.hxx"

using ::com::sun::star::lang::XMultiServiceFactory;

namespace XPath
{
    // factory
    Reference< XInterface > CXPathAPI::_getInstance(const Reference< XMultiServiceFactory >& rSMgr)
    {
        return Reference< XInterface >(static_cast<XXPathAPI*>(new CXPathAPI(rSMgr)));
    }

    // ctor
    CXPathAPI::CXPathAPI(const Reference< XMultiServiceFactory >& rSMgr)
        : m_aFactory(rSMgr)
    {
    }

    const char* CXPathAPI::aImplementationName = "com.sun.star.comp.xml.xpath.XPathAPI";
    const char* CXPathAPI::aSupportedServiceNames[] = {
        "com.sun.star.xml.xpath.XPathAPI",
        NULL
    };

    OUString CXPathAPI::_getImplementationName()
    {
        return OUString::createFromAscii(aImplementationName);
    }

    Sequence<OUString> CXPathAPI::_getSupportedServiceNames()
    {
        Sequence<OUString> aSequence;
        for (int i=0; aSupportedServiceNames[i]!=NULL; i++) {
            aSequence.realloc(i+1);
            aSequence[i]=(OUString::createFromAscii(aSupportedServiceNames[i]));
        }
        return aSequence;
    }

    Sequence< OUString > SAL_CALL CXPathAPI::getSupportedServiceNames()
        throw (RuntimeException)
    {
        return CXPathAPI::_getSupportedServiceNames();
    }

    OUString SAL_CALL CXPathAPI::getImplementationName()
        throw (RuntimeException)
    {
        return CXPathAPI::_getImplementationName();
    }

    sal_Bool SAL_CALL CXPathAPI::supportsService(const OUString& aServiceName)
        throw (RuntimeException)
    {
        Sequence< OUString > supported = CXPathAPI::_getSupportedServiceNames();
        for (sal_Int32 i=0; i<supported.getLength(); i++)
        {
            if (supported[i] == aServiceName) return sal_True;
        }
        return sal_False;
    }

    // -------------------------------------------------------------------

    void SAL_CALL CXPathAPI::registerNS(
            const OUString& aPrefix,
            const OUString& aURI)
        throw (RuntimeException)
    {
        ::osl::MutexGuard const g(m_Mutex);

        m_nsmap.insert(nsmap_t::value_type(aPrefix, aURI));
    }

    void SAL_CALL CXPathAPI::unregisterNS(
            const OUString& aPrefix,
            const OUString& aURI)
        throw (RuntimeException)
    {
        ::osl::MutexGuard const g(m_Mutex);

        if ((m_nsmap.find(aPrefix))->second.equals(aURI)) {
            m_nsmap.erase(aPrefix);
        }
    }

    // register all namespaces stored in the namespace list for this object
    // with the current xpath evaluation context
    static void lcl_registerNamespaces(
            xmlXPathContextPtr ctx,
            const nsmap_t& nsmap)
    {
        nsmap_t::const_iterator i = nsmap.begin();
        OString oprefix, ouri;
        xmlChar *p, *u;
        while (i != nsmap.end())
        {
            oprefix = OUStringToOString(i->first,  RTL_TEXTENCODING_UTF8);
            ouri    = OUStringToOString(i->second, RTL_TEXTENCODING_UTF8);
            p = (xmlChar*)oprefix.getStr();
            u = (xmlChar*)ouri.getStr();
            xmlXPathRegisterNs(ctx, p, u);
            ++i;
        }
    }

    // get all ns decls on a node (and parent nodes, if any)
    static void lcl_collectNamespaces(
            nsmap_t & rNamespaces, Reference< XNode > const& xNamespaceNode)
    {
        DOM::CNode *const pCNode(DOM::CNode::GetImplementation(xNamespaceNode));
        if (!pCNode) { throw RuntimeException(); }

        ::osl::MutexGuard const g(pCNode->GetOwnerDocument().GetMutex());

        xmlNodePtr pNode = pCNode->GetNodePtr();
        while (pNode != 0) {
            xmlNsPtr curDef = pNode->nsDef;
            while (curDef != 0) {
                const xmlChar* xHref = curDef->href;
                OUString aURI((sal_Char*)xHref, strlen((char*)xHref), RTL_TEXTENCODING_UTF8);
                const xmlChar* xPre = curDef->prefix;
                OUString aPrefix((sal_Char*)xPre, strlen((char*)xPre), RTL_TEXTENCODING_UTF8);
                // we could already have this prefix from a child node
                if (rNamespaces.find(aPrefix) == rNamespaces.end())
                {
                    rNamespaces.insert(::std::make_pair(aPrefix, aURI));
                }
                curDef = curDef->next;
            }
            pNode = pNode->parent;
        }
    }

    static void lcl_collectRegisterNamespaces(
            CXPathAPI & rAPI, Reference< XNode > const& xNamespaceNode)
    {
        nsmap_t namespaces;
        lcl_collectNamespaces(namespaces, xNamespaceNode);
        for (nsmap_t::const_iterator iter = namespaces.begin();
                iter != namespaces.end(); ++iter)
        {
            rAPI.registerNS(iter->first, iter->second);
        }
    }

    // register function and variable lookup functions with the current
    // xpath evaluation context
    static void lcl_registerExtensions(
            xmlXPathContextPtr ctx,
            const extensions_t& extensions)
    {
        extensions_t::const_iterator i = extensions.begin();
        while (i != extensions.end())
        {
            Libxml2ExtensionHandle aHandle = (*i)->getLibxml2ExtensionHandle();
            if ( aHandle.functionLookupFunction != 0 )
            {
                xmlXPathRegisterFuncLookup(ctx,
                    reinterpret_cast<xmlXPathFuncLookupFunc>(
                        sal::static_int_cast<sal_IntPtr>(aHandle.functionLookupFunction)),
                    reinterpret_cast<void*>(
                        sal::static_int_cast<sal_IntPtr>(aHandle.functionData)));
            }
            if ( aHandle.variableLookupFunction != 0 )
            {
                xmlXPathRegisterVariableLookup(ctx,
                    reinterpret_cast<xmlXPathVariableLookupFunc>(
                        sal::static_int_cast<sal_IntPtr>(aHandle.variableLookupFunction)),
                    reinterpret_cast<void*>(
                        sal::static_int_cast<sal_IntPtr>(aHandle.variableData)));
            }
            ++i;
        }
    }

    /**
     * Use an XPath string to select a nodelist.
     */
    Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeList(
            const Reference< XNode >& contextNode,
            const OUString& expr)
        throw (RuntimeException, XPathException)
    {
        Reference< XXPathObject > xobj = eval(contextNode, expr);
        return xobj->getNodeList();
    }

    /**
     * same as selectNodeList but registers all name space decalratiosn found on namespaceNode
     */
    Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeListNS(
            const Reference< XNode >&  contextNode,
            const OUString& expr,
            const Reference< XNode >&  namespaceNode)
        throw (RuntimeException, XPathException)
    {
        lcl_collectRegisterNamespaces(*this, namespaceNode);
        return selectNodeList(contextNode, expr);
    }

    /**
     * Same as selectNodeList but returns the first node (if any)
     */
    Reference< XNode > SAL_CALL CXPathAPI::selectSingleNode(
            const Reference< XNode >& contextNode,
            const OUString& expr)
        throw (RuntimeException, XPathException)
    {
        Reference< XNodeList > aList = selectNodeList(contextNode, expr);
        Reference< XNode > aNode = aList->item(0);
        return aNode;
    }

    /**
     * Same as selectSingleNode but registers all namespaces declared on
     * namespaceNode
     */
    Reference< XNode > SAL_CALL CXPathAPI::selectSingleNodeNS(
            const Reference< XNode >& contextNode,
            const OUString& expr,
            const Reference< XNode >&  namespaceNode )
        throw (RuntimeException, XPathException)
    {
        lcl_collectRegisterNamespaces(*this, namespaceNode);
        return selectSingleNode(contextNode, expr);
    }

    static OUString make_error_message(xmlErrorPtr pError)
    {
        ::rtl::OUStringBuffer buf;
        if (pError->message) {
            buf.appendAscii(pError->message);
        }
        int line = pError->line;
        if (line) {
            buf.appendAscii("Line: ");
            buf.append(static_cast<sal_Int32>(line));
            buf.appendAscii("\n");
        }
        int column = pError->int2;
        if (column) {
            buf.appendAscii("Column: ");
            buf.append(static_cast<sal_Int32>(column));
            buf.appendAscii("\n");
        }
        OUString msg = buf.makeStringAndClear();
        return msg;
    }

    extern "C" {

        static void generic_error_func(void *userData, const char *format, ...)
        {
            (void) userData;
            char str[1000];
            va_list args;

            va_start(args, format);
#ifdef _WIN32
#define vsnprintf _vsnprintf
#endif
            vsnprintf(str, sizeof(str), format, args);
            va_end(args);

            ::rtl::OUStringBuffer buf(
                "libxml2 error:\n");
            buf.appendAscii(str);
            OString msg = OUStringToOString(buf.makeStringAndClear(),
                RTL_TEXTENCODING_ASCII_US);
            OSL_FAIL(msg.getStr());
        }

        static void structured_error_func(void * userData, xmlErrorPtr error)
        {
            (void) userData;
            ::rtl::OUStringBuffer buf(
                "libxml2 error:\n");
            if (error) {
                buf.append(make_error_message(error));
            } else {
                buf.append("no error argument!");
            }
            OString msg = OUStringToOString(buf.makeStringAndClear(),
                RTL_TEXTENCODING_ASCII_US);
            OSL_FAIL(msg.getStr());
        }

    } // extern "C"

    /**
     * evaluates an XPath string. relative XPath expressions are evaluated relative to
     * the context Node
     */
    Reference< XXPathObject > SAL_CALL CXPathAPI::eval(
            Reference< XNode > const& xContextNode,
            const OUString& expr)
        throw (RuntimeException, XPathException)
    {
        if (!xContextNode.is()) { throw RuntimeException(); }

        nsmap_t nsmap;
        extensions_t extensions;

        {
            ::osl::MutexGuard const g(m_Mutex);
            nsmap = m_nsmap;
            extensions = m_extensions;
        }

        // get the node and document
        ::rtl::Reference<DOM::CDocument> const pCDoc(
                dynamic_cast<DOM::CDocument*>( DOM::CNode::GetImplementation(
                        xContextNode->getOwnerDocument())));
        if (!pCDoc.is()) { throw RuntimeException(); }

        DOM::CNode *const pCNode = DOM::CNode::GetImplementation(xContextNode);
        if (!pCNode) { throw RuntimeException(); }

        ::osl::MutexGuard const g(pCDoc->GetMutex()); // lock the document!

        xmlNodePtr const pNode = pCNode->GetNodePtr();
        if (!pNode) { throw RuntimeException(); }
        xmlDocPtr pDoc = pNode->doc;

        /* NB: workaround for #i87252#:
           libxml < 2.6.17 considers it an error if the context
           node is the empty document (i.e. its xpathCtx->doc has no
           children). libxml 2.6.17 does not consider it an error.
           Unfortunately, old libxml prints an error message to stderr,
           which (afaik) cannot be turned off in this case, so we handle it.
        */
        if (!pDoc->children) {
            throw XPathException();
        }

        /* Create xpath evaluation context */
        ::boost::shared_ptr<xmlXPathContext> const xpathCtx(
                xmlXPathNewContext(pDoc), xmlXPathFreeContext);
        if (xpathCtx == NULL) { throw XPathException(); }

        // set context node
        xpathCtx->node = pNode;
        // error handling
        xpathCtx->error = structured_error_func;
        xmlSetGenericErrorFunc(NULL, generic_error_func);

        // register namespaces and extension
        lcl_registerNamespaces(xpathCtx.get(), nsmap);
        lcl_registerExtensions(xpathCtx.get(), extensions);

        /* run the query */
        OString o1 = OUStringToOString(expr, RTL_TEXTENCODING_UTF8);
        xmlChar *xStr = (xmlChar*)o1.getStr();
        ::boost::shared_ptr<xmlXPathObject> const xpathObj(
                xmlXPathEval(xStr, xpathCtx.get()), xmlXPathFreeObject);
        if (0 == xpathObj) {
            // OSL_ENSURE(xpathCtx->lastError == NULL, xpathCtx->lastError->message);
            throw XPathException();
        }
        Reference<XXPathObject> const xObj(
                new CXPathObject(pCDoc, pCDoc->GetMutex(), xpathObj));
        return xObj;
    }

    /**
     * same as eval but registers all namespace declarations found on namespaceNode
     */
    Reference< XXPathObject > SAL_CALL CXPathAPI::evalNS(
            const Reference< XNode >& contextNode,
            const OUString& expr,
            const Reference< XNode >& namespaceNode)
        throw (RuntimeException, XPathException)
    {
        lcl_collectRegisterNamespaces(*this, namespaceNode);
        return eval(contextNode, expr);
    }

    /**
     * uses the service manager to create an instance of the service denoted by aName.
     * If the returned object implements the XXPathExtension interface, it is added to the list
     * of extensions that are used when evaluating XPath strings with this XPathAPI instance
     */
    void SAL_CALL CXPathAPI::registerExtension(
            const OUString& aName)
        throw (RuntimeException)
    {
        ::osl::MutexGuard const g(m_Mutex);

        // get extension from service manager
        Reference< XXPathExtension > const xExtension(
                m_aFactory->createInstance(aName), UNO_QUERY_THROW);
        m_extensions.push_back(xExtension);
    }

    /**
     * registers the given extension instance to be used by XPath evaluations performed through this
     * XPathAPI instance
     */
    void SAL_CALL CXPathAPI::registerExtensionInstance(
            Reference< XXPathExtension> const& xExtension)
        throw (RuntimeException)
    {
        if (!xExtension.is()) {
            throw RuntimeException();
        }
        ::osl::MutexGuard const g(m_Mutex);
        m_extensions.push_back( xExtension );
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Reset xmlSetGenericErrorFunc after use<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <xpathapi.hxx>

#include <stdarg.h>
#include <string.h>

#include <libxml/tree.h>
#include <libxml/xmlerror.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>

#include <rtl/ustrbuf.hxx>

#include <nodelist.hxx>
#include <xpathobject.hxx>

#include "../dom/node.hxx"
#include "../dom/document.hxx"

using ::com::sun::star::lang::XMultiServiceFactory;

namespace XPath
{
    // factory
    Reference< XInterface > CXPathAPI::_getInstance(const Reference< XMultiServiceFactory >& rSMgr)
    {
        return Reference< XInterface >(static_cast<XXPathAPI*>(new CXPathAPI(rSMgr)));
    }

    // ctor
    CXPathAPI::CXPathAPI(const Reference< XMultiServiceFactory >& rSMgr)
        : m_aFactory(rSMgr)
    {
    }

    const char* CXPathAPI::aImplementationName = "com.sun.star.comp.xml.xpath.XPathAPI";
    const char* CXPathAPI::aSupportedServiceNames[] = {
        "com.sun.star.xml.xpath.XPathAPI",
        NULL
    };

    OUString CXPathAPI::_getImplementationName()
    {
        return OUString::createFromAscii(aImplementationName);
    }

    Sequence<OUString> CXPathAPI::_getSupportedServiceNames()
    {
        Sequence<OUString> aSequence;
        for (int i=0; aSupportedServiceNames[i]!=NULL; i++) {
            aSequence.realloc(i+1);
            aSequence[i]=(OUString::createFromAscii(aSupportedServiceNames[i]));
        }
        return aSequence;
    }

    Sequence< OUString > SAL_CALL CXPathAPI::getSupportedServiceNames()
        throw (RuntimeException)
    {
        return CXPathAPI::_getSupportedServiceNames();
    }

    OUString SAL_CALL CXPathAPI::getImplementationName()
        throw (RuntimeException)
    {
        return CXPathAPI::_getImplementationName();
    }

    sal_Bool SAL_CALL CXPathAPI::supportsService(const OUString& aServiceName)
        throw (RuntimeException)
    {
        Sequence< OUString > supported = CXPathAPI::_getSupportedServiceNames();
        for (sal_Int32 i=0; i<supported.getLength(); i++)
        {
            if (supported[i] == aServiceName) return sal_True;
        }
        return sal_False;
    }

    // -------------------------------------------------------------------

    void SAL_CALL CXPathAPI::registerNS(
            const OUString& aPrefix,
            const OUString& aURI)
        throw (RuntimeException)
    {
        ::osl::MutexGuard const g(m_Mutex);

        m_nsmap.insert(nsmap_t::value_type(aPrefix, aURI));
    }

    void SAL_CALL CXPathAPI::unregisterNS(
            const OUString& aPrefix,
            const OUString& aURI)
        throw (RuntimeException)
    {
        ::osl::MutexGuard const g(m_Mutex);

        if ((m_nsmap.find(aPrefix))->second.equals(aURI)) {
            m_nsmap.erase(aPrefix);
        }
    }

    // register all namespaces stored in the namespace list for this object
    // with the current xpath evaluation context
    static void lcl_registerNamespaces(
            xmlXPathContextPtr ctx,
            const nsmap_t& nsmap)
    {
        nsmap_t::const_iterator i = nsmap.begin();
        OString oprefix, ouri;
        xmlChar *p, *u;
        while (i != nsmap.end())
        {
            oprefix = OUStringToOString(i->first,  RTL_TEXTENCODING_UTF8);
            ouri    = OUStringToOString(i->second, RTL_TEXTENCODING_UTF8);
            p = (xmlChar*)oprefix.getStr();
            u = (xmlChar*)ouri.getStr();
            xmlXPathRegisterNs(ctx, p, u);
            ++i;
        }
    }

    // get all ns decls on a node (and parent nodes, if any)
    static void lcl_collectNamespaces(
            nsmap_t & rNamespaces, Reference< XNode > const& xNamespaceNode)
    {
        DOM::CNode *const pCNode(DOM::CNode::GetImplementation(xNamespaceNode));
        if (!pCNode) { throw RuntimeException(); }

        ::osl::MutexGuard const g(pCNode->GetOwnerDocument().GetMutex());

        xmlNodePtr pNode = pCNode->GetNodePtr();
        while (pNode != 0) {
            xmlNsPtr curDef = pNode->nsDef;
            while (curDef != 0) {
                const xmlChar* xHref = curDef->href;
                OUString aURI((sal_Char*)xHref, strlen((char*)xHref), RTL_TEXTENCODING_UTF8);
                const xmlChar* xPre = curDef->prefix;
                OUString aPrefix((sal_Char*)xPre, strlen((char*)xPre), RTL_TEXTENCODING_UTF8);
                // we could already have this prefix from a child node
                if (rNamespaces.find(aPrefix) == rNamespaces.end())
                {
                    rNamespaces.insert(::std::make_pair(aPrefix, aURI));
                }
                curDef = curDef->next;
            }
            pNode = pNode->parent;
        }
    }

    static void lcl_collectRegisterNamespaces(
            CXPathAPI & rAPI, Reference< XNode > const& xNamespaceNode)
    {
        nsmap_t namespaces;
        lcl_collectNamespaces(namespaces, xNamespaceNode);
        for (nsmap_t::const_iterator iter = namespaces.begin();
                iter != namespaces.end(); ++iter)
        {
            rAPI.registerNS(iter->first, iter->second);
        }
    }

    // register function and variable lookup functions with the current
    // xpath evaluation context
    static void lcl_registerExtensions(
            xmlXPathContextPtr ctx,
            const extensions_t& extensions)
    {
        extensions_t::const_iterator i = extensions.begin();
        while (i != extensions.end())
        {
            Libxml2ExtensionHandle aHandle = (*i)->getLibxml2ExtensionHandle();
            if ( aHandle.functionLookupFunction != 0 )
            {
                xmlXPathRegisterFuncLookup(ctx,
                    reinterpret_cast<xmlXPathFuncLookupFunc>(
                        sal::static_int_cast<sal_IntPtr>(aHandle.functionLookupFunction)),
                    reinterpret_cast<void*>(
                        sal::static_int_cast<sal_IntPtr>(aHandle.functionData)));
            }
            if ( aHandle.variableLookupFunction != 0 )
            {
                xmlXPathRegisterVariableLookup(ctx,
                    reinterpret_cast<xmlXPathVariableLookupFunc>(
                        sal::static_int_cast<sal_IntPtr>(aHandle.variableLookupFunction)),
                    reinterpret_cast<void*>(
                        sal::static_int_cast<sal_IntPtr>(aHandle.variableData)));
            }
            ++i;
        }
    }

    /**
     * Use an XPath string to select a nodelist.
     */
    Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeList(
            const Reference< XNode >& contextNode,
            const OUString& expr)
        throw (RuntimeException, XPathException)
    {
        Reference< XXPathObject > xobj = eval(contextNode, expr);
        return xobj->getNodeList();
    }

    /**
     * same as selectNodeList but registers all name space decalratiosn found on namespaceNode
     */
    Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeListNS(
            const Reference< XNode >&  contextNode,
            const OUString& expr,
            const Reference< XNode >&  namespaceNode)
        throw (RuntimeException, XPathException)
    {
        lcl_collectRegisterNamespaces(*this, namespaceNode);
        return selectNodeList(contextNode, expr);
    }

    /**
     * Same as selectNodeList but returns the first node (if any)
     */
    Reference< XNode > SAL_CALL CXPathAPI::selectSingleNode(
            const Reference< XNode >& contextNode,
            const OUString& expr)
        throw (RuntimeException, XPathException)
    {
        Reference< XNodeList > aList = selectNodeList(contextNode, expr);
        Reference< XNode > aNode = aList->item(0);
        return aNode;
    }

    /**
     * Same as selectSingleNode but registers all namespaces declared on
     * namespaceNode
     */
    Reference< XNode > SAL_CALL CXPathAPI::selectSingleNodeNS(
            const Reference< XNode >& contextNode,
            const OUString& expr,
            const Reference< XNode >&  namespaceNode )
        throw (RuntimeException, XPathException)
    {
        lcl_collectRegisterNamespaces(*this, namespaceNode);
        return selectSingleNode(contextNode, expr);
    }

    static OUString make_error_message(xmlErrorPtr pError)
    {
        ::rtl::OUStringBuffer buf;
        if (pError->message) {
            buf.appendAscii(pError->message);
        }
        int line = pError->line;
        if (line) {
            buf.appendAscii("Line: ");
            buf.append(static_cast<sal_Int32>(line));
            buf.appendAscii("\n");
        }
        int column = pError->int2;
        if (column) {
            buf.appendAscii("Column: ");
            buf.append(static_cast<sal_Int32>(column));
            buf.appendAscii("\n");
        }
        OUString msg = buf.makeStringAndClear();
        return msg;
    }

    extern "C" {

        static void generic_error_func(void *userData, const char *format, ...)
        {
            (void) userData;
            char str[1000];
            va_list args;

            va_start(args, format);
#ifdef _WIN32
#define vsnprintf _vsnprintf
#endif
            vsnprintf(str, sizeof(str), format, args);
            va_end(args);

            ::rtl::OUStringBuffer buf(
                "libxml2 error:\n");
            buf.appendAscii(str);
            OString msg = OUStringToOString(buf.makeStringAndClear(),
                RTL_TEXTENCODING_ASCII_US);
            OSL_FAIL(msg.getStr());
        }

        static void structured_error_func(void * userData, xmlErrorPtr error)
        {
            (void) userData;
            ::rtl::OUStringBuffer buf(
                "libxml2 error:\n");
            if (error) {
                buf.append(make_error_message(error));
            } else {
                buf.append("no error argument!");
            }
            OString msg = OUStringToOString(buf.makeStringAndClear(),
                RTL_TEXTENCODING_ASCII_US);
            OSL_FAIL(msg.getStr());
        }

    } // extern "C"

    /**
     * evaluates an XPath string. relative XPath expressions are evaluated relative to
     * the context Node
     */
    Reference< XXPathObject > SAL_CALL CXPathAPI::eval(
            Reference< XNode > const& xContextNode,
            const OUString& expr)
        throw (RuntimeException, XPathException)
    {
        if (!xContextNode.is()) { throw RuntimeException(); }

        nsmap_t nsmap;
        extensions_t extensions;

        {
            ::osl::MutexGuard const g(m_Mutex);
            nsmap = m_nsmap;
            extensions = m_extensions;
        }

        // get the node and document
        ::rtl::Reference<DOM::CDocument> const pCDoc(
                dynamic_cast<DOM::CDocument*>( DOM::CNode::GetImplementation(
                        xContextNode->getOwnerDocument())));
        if (!pCDoc.is()) { throw RuntimeException(); }

        DOM::CNode *const pCNode = DOM::CNode::GetImplementation(xContextNode);
        if (!pCNode) { throw RuntimeException(); }

        ::osl::MutexGuard const g(pCDoc->GetMutex()); // lock the document!

        xmlNodePtr const pNode = pCNode->GetNodePtr();
        if (!pNode) { throw RuntimeException(); }
        xmlDocPtr pDoc = pNode->doc;

        /* NB: workaround for #i87252#:
           libxml < 2.6.17 considers it an error if the context
           node is the empty document (i.e. its xpathCtx->doc has no
           children). libxml 2.6.17 does not consider it an error.
           Unfortunately, old libxml prints an error message to stderr,
           which (afaik) cannot be turned off in this case, so we handle it.
        */
        if (!pDoc->children) {
            throw XPathException();
        }

        /* Create xpath evaluation context */
        ::boost::shared_ptr<xmlXPathContext> const xpathCtx(
                xmlXPathNewContext(pDoc), xmlXPathFreeContext);
        if (xpathCtx == NULL) { throw XPathException(); }

        // set context node
        xpathCtx->node = pNode;
        // error handling
        xpathCtx->error = structured_error_func;
        xmlSetGenericErrorFunc(NULL, generic_error_func);

        // register namespaces and extension
        lcl_registerNamespaces(xpathCtx.get(), nsmap);
        lcl_registerExtensions(xpathCtx.get(), extensions);

        /* run the query */
        OString o1 = OUStringToOString(expr, RTL_TEXTENCODING_UTF8);
        xmlChar *xStr = (xmlChar*)o1.getStr();
        ::boost::shared_ptr<xmlXPathObject> const xpathObj(
                xmlXPathEval(xStr, xpathCtx.get()), xmlXPathFreeObject);
        xmlSetGenericErrorFunc(NULL, NULL);
        if (0 == xpathObj) {
            // OSL_ENSURE(xpathCtx->lastError == NULL, xpathCtx->lastError->message);
            throw XPathException();
        }
        Reference<XXPathObject> const xObj(
                new CXPathObject(pCDoc, pCDoc->GetMutex(), xpathObj));
        return xObj;
    }

    /**
     * same as eval but registers all namespace declarations found on namespaceNode
     */
    Reference< XXPathObject > SAL_CALL CXPathAPI::evalNS(
            const Reference< XNode >& contextNode,
            const OUString& expr,
            const Reference< XNode >& namespaceNode)
        throw (RuntimeException, XPathException)
    {
        lcl_collectRegisterNamespaces(*this, namespaceNode);
        return eval(contextNode, expr);
    }

    /**
     * uses the service manager to create an instance of the service denoted by aName.
     * If the returned object implements the XXPathExtension interface, it is added to the list
     * of extensions that are used when evaluating XPath strings with this XPathAPI instance
     */
    void SAL_CALL CXPathAPI::registerExtension(
            const OUString& aName)
        throw (RuntimeException)
    {
        ::osl::MutexGuard const g(m_Mutex);

        // get extension from service manager
        Reference< XXPathExtension > const xExtension(
                m_aFactory->createInstance(aName), UNO_QUERY_THROW);
        m_extensions.push_back(xExtension);
    }

    /**
     * registers the given extension instance to be used by XPath evaluations performed through this
     * XPathAPI instance
     */
    void SAL_CALL CXPathAPI::registerExtensionInstance(
            Reference< XXPathExtension> const& xExtension)
        throw (RuntimeException)
    {
        if (!xExtension.is()) {
            throw RuntimeException();
        }
        ::osl::MutexGuard const g(m_Mutex);
        m_extensions.push_back( xExtension );
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkTobogganImageFilterTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm 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 "itkTobogganImageFilter.h"
#include "itkRecursiveGaussianImageFilter.h"
#include "itkGradientMagnitudeImageFilter.h"
#include "itkGradientMagnitudeRecursiveGaussianImageFilter.h"
#include "itkDiscreteGaussianImageFilter.h"
#include "itkCastImageFilter.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkPNGImageIOFactory.h"
#include "itkPNGImageIO.h"
#include "itkTextOutput.h"
#include "itkImageRegionIterator.h"

void itkTobogganImageFilterTest(int ac, char** av)
{
  // Comment the following if you want to use the itk text output window
  itk::OutputWindow::SetInstance(itk::TextOutput::New());

  if(ac < 3)
    {
    std::cerr << "Usage: " << av[0] << " InputImage BaselineImage [OutputImage]\n";
    exit ( 1 );
    }

  // Register one Factory of PNG readers
  itk::PNGImageIOFactory::RegisterOneFactory();

  typedef unsigned char PixelType;
  typedef itk::Image<unsigned char, 2> InputImageType;
  typedef itk::Image<float, 2> FloatImageType;
  typedef itk::Image<unsigned char, 2> OutputImageType;
  typedef itk::Image<unsigned long, 2> LongImageType;

  // Create a pipeline
  typedef itk::CastImageFilter<InputImageType, FloatImageType> InCastType;
  typedef itk::RecursiveGaussianImageFilter<InputImageType,FloatImageType> GaussianFilterType;
  typedef itk::GradientMagnitudeImageFilter<FloatImageType,FloatImageType> GradientMagnitudeFilterType;
  typedef itk::TobogganImageFilter<FloatImageType> FilterType;
  typedef itk::CastImageFilter<LongImageType, OutputImageType> CastType;
  typedef itk::DiscreteGaussianImageFilter<FloatImageType,FloatImageType> DGIFType;
  typedef itk::GradientMagnitudeRecursiveGaussianImageFilter<FloatImageType,FloatImageType> GMGaussianType;

  FilterType::Pointer toboggan = FilterType::New();
  GaussianFilterType::Pointer gaussian = GaussianFilterType::New();
  GradientMagnitudeFilterType::Pointer magnitude = GradientMagnitudeFilterType::New();
  CastType::Pointer cast = CastType::New();
  InCastType::Pointer incast = InCastType::New();
  DGIFType::Pointer discretegaussian = DGIFType::New();
  GMGaussianType::Pointer gmgaussian = GMGaussianType::New();

  itk::ImageFileReader<InputImageType>::Pointer input
    = itk::ImageFileReader<InputImageType>::New();

  input->SetFileName(av[1]);
  incast->SetInput ( input->GetOutput() );
  gmgaussian->SetInput ( incast->GetOutput() );
  gmgaussian->SetSigma ( 15.0 );
  toboggan->SetInput ( gmgaussian->GetOutput() );
  cast->SetInput ( toboggan->GetOutput() );
  try
    {
    input->Update();
    cast->Update();
    }
  catch (itk::ExceptionObject& e)
    {
    std::cerr << "Exception detected: "  << e.GetDescription();
    exit ( 1 );
    }

  // Try to write it out if we need to...
  if ( ac == 4 )
    {
    itk::PNGImageIO::Pointer io;
    io = itk::PNGImageIO::New();

    itk::ImageFileWriter<OutputImageType>::Pointer writer;
    writer = itk::ImageFileWriter<OutputImageType>::New();
    writer->SetInput( cast->GetOutput() );
    writer->SetFileName( av[3] );
    writer->SetImageIO( io );
    writer->Update();
    }

  // now read the regression image
  itk::ImageFileReader<OutputImageType>::Pointer baseline
    = itk::ImageFileReader<OutputImageType>::New();
    baseline->SetFileName(av[2]);

  try
    {
    baseline->Update();
    }
  catch (itk::ImageFileReaderException& e)
    {
    std::cerr << "Exception in file reader: "  << e.GetDescription() << std::endl;
    exit ( 1 );
    }

  // compare the two images
  itk::ImageRegionIterator<OutputImageType> it(cast->GetOutput(),cast->GetOutput()->GetBufferedRegion());
  itk::ImageRegionIterator<OutputImageType> rit(baseline->GetOutput(),baseline->GetOutput()->GetBufferedRegion());
  int status = 0;
  unsigned long int classes = 0;
  while (!it.IsAtEnd())
    {
    if (it.Get() != rit.Get())
      {
      std::cout << "Different pixel at: " << it.GetIndex() << " Baseline: " << (int)rit.Get() << " Computed: " << (int)it.Get() << std::endl;
      status++;
      }
    if ( it.Get() > classes )
      {
      classes = it.Get();
      }
    ++it;
    ++rit;
    }
  std::cout << "Found " << classes << " Different objects" << std::endl;
  std::cout << "Found " << status << " pixel(s) different" << std::endl;
  if ( status > 1 )
    {
    exit ( 1 );
    }
  exit ( 0 );
}
<commit_msg>FIX: Tests must return an int, not call exit().<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkTobogganImageFilterTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm 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 "itkTobogganImageFilter.h"
#include "itkRecursiveGaussianImageFilter.h"
#include "itkGradientMagnitudeImageFilter.h"
#include "itkGradientMagnitudeRecursiveGaussianImageFilter.h"
#include "itkDiscreteGaussianImageFilter.h"
#include "itkCastImageFilter.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkPNGImageIOFactory.h"
#include "itkPNGImageIO.h"
#include "itkTextOutput.h"
#include "itkImageRegionIterator.h"

int itkTobogganImageFilterTest(int ac, char** av)
{
  // Comment the following if you want to use the itk text output window
  itk::OutputWindow::SetInstance(itk::TextOutput::New());

  if(ac < 3)
    {
    std::cerr << "Usage: " << av[0] << " InputImage BaselineImage [OutputImage]\n";
    exit ( 1 );
    }

  // Register one Factory of PNG readers
  itk::PNGImageIOFactory::RegisterOneFactory();

  typedef unsigned char PixelType;
  typedef itk::Image<unsigned char, 2> InputImageType;
  typedef itk::Image<float, 2> FloatImageType;
  typedef itk::Image<unsigned char, 2> OutputImageType;
  typedef itk::Image<unsigned long, 2> LongImageType;

  // Create a pipeline
  typedef itk::CastImageFilter<InputImageType, FloatImageType> InCastType;
  typedef itk::RecursiveGaussianImageFilter<InputImageType,FloatImageType> GaussianFilterType;
  typedef itk::GradientMagnitudeImageFilter<FloatImageType,FloatImageType> GradientMagnitudeFilterType;
  typedef itk::TobogganImageFilter<FloatImageType> FilterType;
  typedef itk::CastImageFilter<LongImageType, OutputImageType> CastType;
  typedef itk::DiscreteGaussianImageFilter<FloatImageType,FloatImageType> DGIFType;
  typedef itk::GradientMagnitudeRecursiveGaussianImageFilter<FloatImageType,FloatImageType> GMGaussianType;

  FilterType::Pointer toboggan = FilterType::New();
  GaussianFilterType::Pointer gaussian = GaussianFilterType::New();
  GradientMagnitudeFilterType::Pointer magnitude = GradientMagnitudeFilterType::New();
  CastType::Pointer cast = CastType::New();
  InCastType::Pointer incast = InCastType::New();
  DGIFType::Pointer discretegaussian = DGIFType::New();
  GMGaussianType::Pointer gmgaussian = GMGaussianType::New();

  itk::ImageFileReader<InputImageType>::Pointer input
    = itk::ImageFileReader<InputImageType>::New();

  input->SetFileName(av[1]);
  incast->SetInput ( input->GetOutput() );
  gmgaussian->SetInput ( incast->GetOutput() );
  gmgaussian->SetSigma ( 15.0 );
  toboggan->SetInput ( gmgaussian->GetOutput() );
  cast->SetInput ( toboggan->GetOutput() );
  try
    {
    input->Update();
    cast->Update();
    }
  catch (itk::ExceptionObject& e)
    {
    std::cerr << "Exception detected: "  << e.GetDescription();
    exit ( 1 );
    }

  // Try to write it out if we need to...
  if ( ac == 4 )
    {
    itk::PNGImageIO::Pointer io;
    io = itk::PNGImageIO::New();

    itk::ImageFileWriter<OutputImageType>::Pointer writer;
    writer = itk::ImageFileWriter<OutputImageType>::New();
    writer->SetInput( cast->GetOutput() );
    writer->SetFileName( av[3] );
    writer->SetImageIO( io );
    writer->Update();
    }

  // now read the regression image
  itk::ImageFileReader<OutputImageType>::Pointer baseline
    = itk::ImageFileReader<OutputImageType>::New();
    baseline->SetFileName(av[2]);

  try
    {
    baseline->Update();
    }
  catch (itk::ImageFileReaderException& e)
    {
    std::cerr << "Exception in file reader: "  << e.GetDescription() << std::endl;
    exit ( 1 );
    }

  // compare the two images
  itk::ImageRegionIterator<OutputImageType> it(cast->GetOutput(),cast->GetOutput()->GetBufferedRegion());
  itk::ImageRegionIterator<OutputImageType> rit(baseline->GetOutput(),baseline->GetOutput()->GetBufferedRegion());
  int status = 0;
  unsigned long int classes = 0;
  while (!it.IsAtEnd())
    {
    if (it.Get() != rit.Get())
      {
      std::cout << "Different pixel at: " << it.GetIndex() << " Baseline: " << (int)rit.Get() << " Computed: " << (int)it.Get() << std::endl;
      status++;
      }
    if ( it.Get() > classes )
      {
      classes = it.Get();
      }
    ++it;
    ++rit;
    }
  std::cout << "Found " << classes << " Different objects" << std::endl;
  std::cout << "Found " << status << " pixel(s) different" << std::endl;
  if ( status > 1 )
    {
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "CollisionsExample.h"
#include "../EventManager.h"
#include "../DrawUtils.h"
#include "../Math/ofDraw.h"

using namespace math;

math::Vector3D CollisionsExample::getElementColor(const ColliderWrapper& wrapper) {
	return wrapper.selected ? Vector3D(255, 255, 255) :(
		wrapper.intersects ? Vector3D(0, 255, 0) : wrapper.defaultColor);
}

void CollisionsExample::setSelected(int id) {
	for (auto i = 0; i < wrappers.size(); i++) {
		wrappers[i].selected = wrappers[i].id == id;
		if (wrappers[i].selected) currentSelected = &wrappers[i];
	}
}

void CollisionsExample::drawElement(const ColliderWrapper& tmp) const
{
	auto aabbDraw = make_shared<ofAABB_DrawHelper>();
	auto bcDraw = make_shared<ofBC_DrawHelper>();

	cg::setColor(getElementColor(tmp));
	if (tmp.boxOrCircle == 1) {
		auto elem = static_cast<AABB*>(tmp.mathElement);
		elem->draw(aabbDraw);
		cg::drawBox(elem->p + elem->s / 2, elem->s);
	}
	else if (tmp.boxOrCircle == 2) {
		auto elem = static_cast<BoundingCircle*>(tmp.mathElement);
		elem->draw(bcDraw);
		cg::drawCircle(elem->p, elem->radius);
	}
}

bool CollisionsExample::testCollision(const ColliderWrapper& wrapper)
{
	//Another solution would be plan some kind of inheritance in AABB and BoundingBox to make polymorphism
	auto c1 = wrapper.boxOrCircle == 1 ?
		static_cast<AABB*>(wrapper.mathElement) :
		nullptr;
	auto c2 = wrapper.boxOrCircle == 2 ?
		static_cast<BoundingCircle*>(wrapper.mathElement) :
		nullptr;

	for (auto i = 0; i < wrappers.size(); i++) {
		auto tmp = wrappers[i];
		if (tmp.id == wrapper.id) continue;

		if (tmp.boxOrCircle == 1) {
			auto elem = static_cast<AABB*>(tmp.mathElement);
			if (c1 != nullptr && elem->intersects(*c1))
				return true;
			if (c2 != nullptr && elem->intersects(*c2)) return true;
		} else if (tmp.boxOrCircle == 2) {
			auto elem = static_cast<BoundingCircle*>(tmp.mathElement);
			if (c1 != nullptr && elem->intersects(*c1)) return true;
			if (c2 != nullptr && elem->intersects(*c2)) return true;
		}
	}

	return false;
}

CollisionsExample::CollisionsExample(): currentSelected(nullptr) {
}

void CollisionsExample::init()
{
	wrappers[0].mathElement = &boxRed;
	wrappers[0].id = 0;
	wrappers[0].defaultColor = Vector3D(255, 0, 0);
	wrappers[0].boxOrCircle = 1;
	wrappers[0].position.set(200, 200);
	wrappers[0].size = 100;
	boxRed.position.set(wrappers[0].position);
	boxRed.size.set(wrappers[0].size, wrappers[0].size);

	wrappers[1].mathElement = &boxBlue;
	wrappers[1].id = 1;
	wrappers[1].defaultColor = Vector3D(0, 0, 255);
	wrappers[1].boxOrCircle = 1;
	wrappers[1].position.set(600, 500);
	wrappers[1].size = 100;
	boxBlue.position.set(wrappers[1].position);
	boxBlue.size.set(wrappers[1].size, wrappers[1].size);

	wrappers[2].mathElement = &circleYellow;
	wrappers[2].id = 2;
	wrappers[2].defaultColor = Vector3D(255, 255, 0);
	wrappers[2].boxOrCircle = 2;
	wrappers[2].position.set(200, 500);
	wrappers[2].size = 80;
	circleYellow.position.set(wrappers[2].position);
	circleYellow.radius = wrappers[2].size;

	wrappers[3].mathElement = &circleCyan;
	wrappers[3].id = 3;
	wrappers[3].defaultColor = Vector3D(0, 255, 255);
	wrappers[3].boxOrCircle = 2;
	wrappers[3].position.set(600, 200);
	wrappers[3].size = 80;
	circleCyan.position.set(wrappers[3].position);
	circleCyan.radius = wrappers[3].size;

	currentSelected = &wrappers[0];
}

void CollisionsExample::update()
{
	mouse = Vector2D(ofGetMouseX(), ofGetHeight() - ofGetMouseY())
		- (currentSelected->boxOrCircle == 1 ? Vector2D(currentSelected->size, currentSelected->size) / 2 : Vector2D());
	setSelected(EventManager::getLastKeyPressed() - '0' - 1);

	currentSelected->selected = true; //Workaround for the first selection (without input)
	currentSelected->position = mouse;

	if (KEY(OF_KEY_UP)) currentSelected->size++;
	if (KEY(OF_KEY_DOWN)) currentSelected->size--;

	for (auto i = 0; i < wrappers.size(); i++) {
		auto tmp = &wrappers[i];
		tmp->intersects = testCollision(*tmp);

		cg::setColor(getElementColor(*tmp));
		if (tmp->boxOrCircle == 1) {
			auto elem = static_cast<AABB*>(tmp->mathElement);
			elem->position = tmp->position;
			elem->size.set(tmp->size, tmp->size);
		} else if (tmp->boxOrCircle == 2) {
			auto elem = static_cast<BoundingCircle*>(tmp->mathElement);
			elem->position = tmp->position;
			elem->radius = tmp->size;
		}
	}
}

void CollisionsExample::draw()
{
	for(auto i = 0; i < wrappers.size(); i++) {
		auto tmp = wrappers[i];
		if(tmp.selected) continue;
		drawElement(tmp);
	}
	drawElement(*currentSelected);
}

void CollisionsExample::close()
{
}

IScreen* CollisionsExample::nextScreen()
{
	return this;
}

CollisionsExample::~CollisionsExample()
{
}
<commit_msg>BC VS BC working<commit_after>#include "CollisionsExample.h"
#include "../EventManager.h"
#include "../DrawUtils.h"
#include "../Math/ofDraw.h"

using namespace math;

math::Vector3D CollisionsExample::getElementColor(const ColliderWrapper& wrapper) {
	return wrapper.selected ? Vector3D(255, 255, 255) :(
		wrapper.intersects ? Vector3D(0, 255, 0) : wrapper.defaultColor);
}

void CollisionsExample::setSelected(int id) {
	for (auto i = 0; i < wrappers.size(); i++) {
		wrappers[i].selected = wrappers[i].id == id;
		if (wrappers[i].selected) currentSelected = &wrappers[i];
	}
}

void CollisionsExample::drawElement(const ColliderWrapper& tmp) const
{
	auto aabbDraw = make_shared<ofAABB_DrawHelper>();
	auto bcDraw = make_shared<ofBC_DrawHelper>();

	cg::setColor(getElementColor(tmp));
	if (tmp.boxOrCircle == 1) {
		auto elem = static_cast<AABB*>(tmp.mathElement);
		elem->draw(aabbDraw);
		cg::drawBox(elem->p + elem->s / 2, elem->s);
	}
	else if (tmp.boxOrCircle == 2) {
		auto elem = static_cast<BoundingCircle*>(tmp.mathElement);
		elem->draw(bcDraw);
		cg::drawCircle(elem->p, elem->radius);
	}
}

bool CollisionsExample::testCollision(const ColliderWrapper& wrapper)
{
	//Another solution would be plan some kind of inheritance in AABB and BoundingBox to make polymorphism
	auto c1 = wrapper.boxOrCircle == 1 ?
		static_cast<AABB*>(wrapper.mathElement) :
		nullptr;
	auto c2 = wrapper.boxOrCircle == 2 ?
		static_cast<BoundingCircle*>(wrapper.mathElement) :
		nullptr;

	for (auto i = 0; i < wrappers.size(); i++) {
		auto tmp = wrappers[i];
		if (tmp.id == wrapper.id) continue;

		if (tmp.boxOrCircle == 1) {
			auto elem = static_cast<AABB*>(tmp.mathElement);
			if (c1 != nullptr && elem->intersects(*c1))
				return true;
			if (c2 != nullptr && elem->intersects(*c2)) return true;
		} else if (tmp.boxOrCircle == 2) {
			auto elem = static_cast<BoundingCircle*>(tmp.mathElement);
			if (c1 != nullptr && elem->intersects(*c1)) return true;
			if (c2 != nullptr && elem->intersects(*c2)) return true;
		}
	}

	return false;
}

CollisionsExample::CollisionsExample(): currentSelected(nullptr) {
}

void CollisionsExample::init()
{
	wrappers[0].mathElement = &boxRed;
	wrappers[0].id = 0;
	wrappers[0].defaultColor = Vector3D(255, 0, 0);
	wrappers[0].boxOrCircle = 1;
	wrappers[0].position.set(200, 200);
	wrappers[0].size = 100;
	boxRed.position.set(wrappers[0].position);
	boxRed.size.set(wrappers[0].size, wrappers[0].size);

	wrappers[1].mathElement = &boxBlue;
	wrappers[1].id = 1;
	wrappers[1].defaultColor = Vector3D(0, 0, 255);
	wrappers[1].boxOrCircle = 1;
	wrappers[1].position.set(600, 500);
	wrappers[1].size = 100;
	boxBlue.position.set(wrappers[1].position);
	boxBlue.size.set(wrappers[1].size, wrappers[1].size);

	wrappers[2].mathElement = &circleYellow;
	wrappers[2].id = 2;
	wrappers[2].defaultColor = Vector3D(255, 255, 0);
	wrappers[2].boxOrCircle = 2;
	wrappers[2].position.set(200, 500);
	wrappers[2].size = 80;
	circleYellow.position.set(wrappers[2].position);
	circleYellow.radius = wrappers[2].size;

	wrappers[3].mathElement = &circleCyan;
	wrappers[3].id = 3;
	wrappers[3].defaultColor = Vector3D(0, 255, 255);
	wrappers[3].boxOrCircle = 2;
	wrappers[3].position.set(600, 200);
	wrappers[3].size = 80;
	circleCyan.position.set(wrappers[3].position);
	circleCyan.radius = wrappers[3].size;

	currentSelected = &wrappers[0];
}

void CollisionsExample::update()
{
	mouse = Vector2D(ofGetMouseX(), ofGetHeight() - ofGetMouseY())
		- (currentSelected->boxOrCircle == 1 ? Vector2D(currentSelected->size, currentSelected->size) / 2 : Vector2D());
	setSelected(EventManager::getLastKeyPressed() - '0' - 1);

	currentSelected->selected = true; //Workaround for the first selection (without input)
	currentSelected->position = mouse;

	if (KEY(OF_KEY_UP)) currentSelected->size += 60 * ofGetLastFrameTime();
	if (KEY(OF_KEY_DOWN)) currentSelected->size -= 60 * ofGetLastFrameTime();

	for (auto i = 0; i < wrappers.size(); i++) {
		auto tmp = &wrappers[i];
		tmp->intersects = testCollision(*tmp);

		cg::setColor(getElementColor(*tmp));
		if (tmp->boxOrCircle == 1) {
			auto elem = static_cast<AABB*>(tmp->mathElement);
			elem->position = tmp->position;
			elem->size.set(tmp->size, tmp->size);
		} else if (tmp->boxOrCircle == 2) {
			auto elem = static_cast<BoundingCircle*>(tmp->mathElement);
			elem->position = tmp->position;
			elem->radius = tmp->size;
		}
	}
}

void CollisionsExample::draw()
{
	for(auto i = 0; i < wrappers.size(); i++) {
		auto tmp = wrappers[i];
		if(tmp.selected) continue;
		drawElement(tmp);
	}
	drawElement(*currentSelected);
}

void CollisionsExample::close()
{
}

IScreen* CollisionsExample::nextScreen()
{
	return this;
}

CollisionsExample::~CollisionsExample()
{
}
<|endoftext|>