<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 .
 */
#ifndef INCLUDED_VBAHELPER_SOURCE_MSFORMS_VBACONTROL_HXX
#define INCLUDED_VBAHELPER_SOURCE_MSFORMS_VBACONTROL_HXX

#include <cppuhelper/implbase1.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/script/XDefaultProperty.hpp>
#include <com/sun/star/drawing/XControlShape.hpp>
#include <com/sun/star/awt/XControl.hpp>
#include <com/sun/star/awt/XWindowPeer.hpp>
#include <com/sun/star/script/ScriptEvent.hpp>
#include <ooo/vba/msforms/XControl.hpp>

#include <vbahelper/vbahelper.hxx>
#include <vbahelper/vbahelperinterface.hxx>
#include <memory>

//typedef ::cppu::WeakImplHelper1< ov::msforms::XControl > ControlImpl_BASE;
//template SAL_DLLPUBLIC_IMPORT InheritedHelperInterfaceImpl1< ov::msforms::XControl >;
typedef InheritedHelperInterfaceImpl1< ov::msforms::XControl > ControlImpl_BASE;

class ScVbaControl : public ControlImpl_BASE
{
private:
    com::sun::star::uno::Reference< com::sun::star::lang::XEventListener > m_xEventListener;
    com::sun::star::uno::Reference< com::sun::star::awt::XControl > m_xEmptyFormControl;
protected:
    // awt control has nothing similar to Tag property of Mso controls,
    // whether it is necessary is another question
    OUString m_aControlTag;

    bool bIsDialog;
    OUString m_sLibraryAndCodeName;
    std::unique_ptr< ov::AbstractGeometryAttributes > mpGeometryHelper;
    css::uno::Reference< css::beans::XPropertySet > m_xProps;
    css::uno::Reference< css::uno::XInterface > m_xControl;
    css::uno::Reference< css::frame::XModel > m_xModel;

    css::uno::Reference< css::awt::XWindowPeer > getWindowPeer() throw (css::uno::RuntimeException);
    void fireChangeEvent();
    void fireClickEvent();
public:
    ScVbaControl( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext,
                    const css::uno::Reference< css::uno::XInterface >& xControl, const css::uno::Reference< css::frame::XModel >& xModel, ov::AbstractGeometryAttributes* pHelper );
    virtual ~ScVbaControl();
    // This class will own the helper, so make sure it is allocated from
    // the heap
    void setGeometryHelper( ov::AbstractGeometryAttributes* pHelper );
    // sets the name of the associated library ( used for UserForm controls )
    void setLibraryAndCodeName( const OUString& sLibCodeName ) { m_sLibraryAndCodeName = sLibCodeName; }
    OUString getLibraryAndCodeName() const { return m_sLibraryAndCodeName; }

    // XControl
    virtual sal_Bool SAL_CALL getEnabled() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setEnabled( sal_Bool _enabled ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual sal_Bool SAL_CALL getVisible() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setVisible( sal_Bool _visible ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual double SAL_CALL getHeight() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setHeight( double _height ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual double SAL_CALL getWidth() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setWidth( double _width ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual double SAL_CALL getLeft() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setLeft( double _left ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual double SAL_CALL getTop() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setTop( double _top ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL SetFocus(  ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL Move( double Left, double Top, const ::com::sun::star::uno::Any& Width, const ::com::sun::star::uno::Any& Height ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL fireEvent( const css::script::ScriptEvent& evt ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;

    virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getObject() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual OUString SAL_CALL getControlSource() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setControlSource( const OUString& _controlsource ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual OUString SAL_CALL getRowSource() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setRowSource( const OUString& _rowsource ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual OUString SAL_CALL getName() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setName( const OUString& _name ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual OUString SAL_CALL getControlTipText() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setControlTipText( const OUString& ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual OUString SAL_CALL getTag() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setTag( const OUString& aTag ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual sal_Int32 SAL_CALL getTabIndex() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setTabIndex( sal_Int32 nTabIndex ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual ::sal_Int32 SAL_CALL getMousePointer() throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setMousePointer( ::sal_Int32 _mousepointer ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    //remove resource because ooo.vba.excel.XControl is a wrapper of com.sun.star.drawing.XControlShape
    void removeResource() throw( css::uno::RuntimeException );
    virtual ::sal_Int32 SAL_CALL getForeColor() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL setForeColor( ::sal_Int32 _forecolor ) throw (::com::sun::star::uno::RuntimeException);
    //XHelperInterface
    virtual OUString getServiceImplName() SAL_OVERRIDE;
    virtual css::uno::Sequence<OUString> getServiceNames() SAL_OVERRIDE;
    //General helper methods for properties (may or maynot be relevant for all
    //controls)
    sal_Int32 getBackColor() throw (css::uno::RuntimeException);
    void setBackColor( sal_Int32 nBackColor ) throw (css::uno::RuntimeException);
    bool getAutoSize() throw (css::uno::RuntimeException);
    void setAutoSize( bool bAutoSize ) throw (css::uno::RuntimeException);
    bool getLocked() throw (css::uno::RuntimeException);
    void setLocked( bool bAutoSize ) throw (css::uno::RuntimeException);
};

class ScVbaControlFactory
{
public:
    static css::uno::Reference< ov::msforms::XControl > createShapeControl(
        const css::uno::Reference< css::uno::XComponentContext >& xContext,
        const css::uno::Reference< css::drawing::XControlShape >& xControlShape,
        const css::uno::Reference< css::frame::XModel >& xModel ) throw (css::uno::RuntimeException);

    static css::uno::Reference< ov::msforms::XControl > createUserformControl(
        const css::uno::Reference< css::uno::XComponentContext >& xContext,
        const css::uno::Reference< css::awt::XControl >& xControl,
        const css::uno::Reference< css::awt::XControl >& xDialog,
        const css::uno::Reference< css::frame::XModel >& xModel,
        double fOffsetX, double fOffsetY ) throw (css::uno::RuntimeException);

private:
    ScVbaControlFactory();
    ~ScVbaControlFactory();
};

#endif // INCLUDED_VBAHELPER_SOURCE_MSFORMS_VBACONTROL_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>loplugin:deletedspecial<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 .
 */
#ifndef INCLUDED_VBAHELPER_SOURCE_MSFORMS_VBACONTROL_HXX
#define INCLUDED_VBAHELPER_SOURCE_MSFORMS_VBACONTROL_HXX

#include <cppuhelper/implbase1.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/script/XDefaultProperty.hpp>
#include <com/sun/star/drawing/XControlShape.hpp>
#include <com/sun/star/awt/XControl.hpp>
#include <com/sun/star/awt/XWindowPeer.hpp>
#include <com/sun/star/script/ScriptEvent.hpp>
#include <ooo/vba/msforms/XControl.hpp>

#include <vbahelper/vbahelper.hxx>
#include <vbahelper/vbahelperinterface.hxx>
#include <memory>

//typedef ::cppu::WeakImplHelper1< ov::msforms::XControl > ControlImpl_BASE;
//template SAL_DLLPUBLIC_IMPORT InheritedHelperInterfaceImpl1< ov::msforms::XControl >;
typedef InheritedHelperInterfaceImpl1< ov::msforms::XControl > ControlImpl_BASE;

class ScVbaControl : public ControlImpl_BASE
{
private:
    com::sun::star::uno::Reference< com::sun::star::lang::XEventListener > m_xEventListener;
    com::sun::star::uno::Reference< com::sun::star::awt::XControl > m_xEmptyFormControl;
protected:
    // awt control has nothing similar to Tag property of Mso controls,
    // whether it is necessary is another question
    OUString m_aControlTag;

    bool bIsDialog;
    OUString m_sLibraryAndCodeName;
    std::unique_ptr< ov::AbstractGeometryAttributes > mpGeometryHelper;
    css::uno::Reference< css::beans::XPropertySet > m_xProps;
    css::uno::Reference< css::uno::XInterface > m_xControl;
    css::uno::Reference< css::frame::XModel > m_xModel;

    css::uno::Reference< css::awt::XWindowPeer > getWindowPeer() throw (css::uno::RuntimeException);
    void fireChangeEvent();
    void fireClickEvent();
public:
    ScVbaControl( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext,
                    const css::uno::Reference< css::uno::XInterface >& xControl, const css::uno::Reference< css::frame::XModel >& xModel, ov::AbstractGeometryAttributes* pHelper );
    virtual ~ScVbaControl();
    // This class will own the helper, so make sure it is allocated from
    // the heap
    void setGeometryHelper( ov::AbstractGeometryAttributes* pHelper );
    // sets the name of the associated library ( used for UserForm controls )
    void setLibraryAndCodeName( const OUString& sLibCodeName ) { m_sLibraryAndCodeName = sLibCodeName; }
    OUString getLibraryAndCodeName() const { return m_sLibraryAndCodeName; }

    // XControl
    virtual sal_Bool SAL_CALL getEnabled() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setEnabled( sal_Bool _enabled ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual sal_Bool SAL_CALL getVisible() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setVisible( sal_Bool _visible ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual double SAL_CALL getHeight() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setHeight( double _height ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual double SAL_CALL getWidth() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setWidth( double _width ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual double SAL_CALL getLeft() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setLeft( double _left ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual double SAL_CALL getTop() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setTop( double _top ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL SetFocus(  ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL Move( double Left, double Top, const ::com::sun::star::uno::Any& Width, const ::com::sun::star::uno::Any& Height ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL fireEvent( const css::script::ScriptEvent& evt ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;

    virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getObject() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual OUString SAL_CALL getControlSource() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setControlSource( const OUString& _controlsource ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual OUString SAL_CALL getRowSource() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setRowSource( const OUString& _rowsource ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual OUString SAL_CALL getName() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setName( const OUString& _name ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual OUString SAL_CALL getControlTipText() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setControlTipText( const OUString& ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual OUString SAL_CALL getTag() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setTag( const OUString& aTag ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual sal_Int32 SAL_CALL getTabIndex() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setTabIndex( sal_Int32 nTabIndex ) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual ::sal_Int32 SAL_CALL getMousePointer() throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    virtual void SAL_CALL setMousePointer( ::sal_Int32 _mousepointer ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
    //remove resource because ooo.vba.excel.XControl is a wrapper of com.sun.star.drawing.XControlShape
    void removeResource() throw( css::uno::RuntimeException );
    virtual ::sal_Int32 SAL_CALL getForeColor() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL setForeColor( ::sal_Int32 _forecolor ) throw (::com::sun::star::uno::RuntimeException);
    //XHelperInterface
    virtual OUString getServiceImplName() SAL_OVERRIDE;
    virtual css::uno::Sequence<OUString> getServiceNames() SAL_OVERRIDE;
    //General helper methods for properties (may or maynot be relevant for all
    //controls)
    sal_Int32 getBackColor() throw (css::uno::RuntimeException);
    void setBackColor( sal_Int32 nBackColor ) throw (css::uno::RuntimeException);
    bool getAutoSize() throw (css::uno::RuntimeException);
    void setAutoSize( bool bAutoSize ) throw (css::uno::RuntimeException);
    bool getLocked() throw (css::uno::RuntimeException);
    void setLocked( bool bAutoSize ) throw (css::uno::RuntimeException);
};

namespace ScVbaControlFactory
{
    css::uno::Reference< ov::msforms::XControl > createShapeControl(
        const css::uno::Reference< css::uno::XComponentContext >& xContext,
        const css::uno::Reference< css::drawing::XControlShape >& xControlShape,
        const css::uno::Reference< css::frame::XModel >& xModel ) throw (css::uno::RuntimeException);

    css::uno::Reference< ov::msforms::XControl > createUserformControl(
        const css::uno::Reference< css::uno::XComponentContext >& xContext,
        const css::uno::Reference< css::awt::XControl >& xControl,
        const css::uno::Reference< css::awt::XControl >& xDialog,
        const css::uno::Reference< css::frame::XModel >& xModel,
        double fOffsetX, double fOffsetY ) throw (css::uno::RuntimeException);
}

#endif // INCLUDED_VBAHELPER_SOURCE_MSFORMS_VBACONTROL_HXX

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


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

#include "app/l10n_util.h"
#include "base/string_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/progress_bar.h"

namespace views {

TEST(ProgressBarTest, ProgressProperty) {
  ProgressBar bar;
  bar.SetProgress(-1);
  int progress = bar.GetProgress();
  EXPECT_EQ(0, progress);
  bar.SetProgress(300);
  progress = bar.GetProgress();
  EXPECT_EQ(100, progress);
  bar.SetProgress(62);
  progress = bar.GetProgress();
  EXPECT_EQ(62, progress);
}

TEST(ProgressBarTest, TooltipTextProperty) {
  ProgressBar bar;
  std::wstring tooltip = L"Some text";
  EXPECT_FALSE(bar.GetTooltipText(gfx::Point(), &tooltip));
  EXPECT_EQ(L"", tooltip);
  std::wstring tooltip_text = L"My progress";
  bar.SetTooltipText(tooltip_text);
  EXPECT_TRUE(bar.GetTooltipText(gfx::Point(), &tooltip));
  EXPECT_EQ(tooltip_text, tooltip);
}

TEST(ProgressBarTest, Accessibility) {
  ProgressBar bar;
  bar.SetProgress(62);

  AccessibilityTypes::Role role;
  EXPECT_TRUE(bar.GetAccessibleRole(&role));
  EXPECT_EQ(AccessibilityTypes::ROLE_TEXT, role);

  // TODO(denisromanov): Test accessibility text here when it's implemented.

  AccessibilityTypes::State state;
  EXPECT_TRUE(bar.GetAccessibleState(&state));
  EXPECT_EQ(AccessibilityTypes::STATE_READONLY, state);
}

}  // namespace views
<commit_msg>Added unit test for the views::ProgressBar::AddProgress method.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "app/l10n_util.h"
#include "base/string_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/progress_bar.h"

namespace views {

TEST(ProgressBarTest, ProgressProperty) {
  ProgressBar bar;
  bar.SetProgress(-1);
  int progress = bar.GetProgress();
  EXPECT_EQ(0, progress);
  bar.SetProgress(300);
  progress = bar.GetProgress();
  EXPECT_EQ(100, progress);
  bar.SetProgress(62);
  progress = bar.GetProgress();
  EXPECT_EQ(62, progress);
}

TEST(ProgressBarTest, AddProgressMethod) {
  ProgressBar bar;
  bar.SetProgress(10);
  bar.AddProgress(22);
  int progress = bar.GetProgress();
  EXPECT_EQ(32, progress);
  bar.AddProgress(200);
  progress = bar.GetProgress();
  EXPECT_EQ(100, progress);
}

TEST(ProgressBarTest, TooltipTextProperty) {
  ProgressBar bar;
  std::wstring tooltip = L"Some text";
  EXPECT_FALSE(bar.GetTooltipText(gfx::Point(), &tooltip));
  EXPECT_EQ(L"", tooltip);
  std::wstring tooltip_text = L"My progress";
  bar.SetTooltipText(tooltip_text);
  EXPECT_TRUE(bar.GetTooltipText(gfx::Point(), &tooltip));
  EXPECT_EQ(tooltip_text, tooltip);
}

TEST(ProgressBarTest, Accessibility) {
  ProgressBar bar;
  bar.SetProgress(62);

  AccessibilityTypes::Role role;
  EXPECT_TRUE(bar.GetAccessibleRole(&role));
  EXPECT_EQ(AccessibilityTypes::ROLE_TEXT, role);

  // TODO(denisromanov): Test accessibility text here when it's implemented.

  AccessibilityTypes::State state;
  EXPECT_TRUE(bar.GetAccessibleState(&state));
  EXPECT_EQ(AccessibilityTypes::STATE_READONLY, state);
}

}  // namespace views
<|endoftext|>


<commit_before>// Virvo - Virtual Reality Volume Rendering
// Copyright (C) 1999-2003 University of Stuttgart, 2004-2005 Brown University
// Contact: Jurgen P. Schulze, jschulze@ucsd.edu
//
// This file is part of Virvo.
//
// Virvo is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library (see license.txt); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include "vvcompress.h"
#include "vvcompressedvector.h"

#ifdef HAVE_CONFIG_H
#include "vvconfig.h"
#endif

#ifdef HAVE_JPEGTURBO
#include <stdio.h>
#include <jpeglib.h>
#if !defined(LIBJPEG_TURBO_VERSION)
#undef HAVE_JPEGTURBO
#endif
#if !defined(JCS_EXTENSIONS) || !defined(JCS_ALPHA_EXTENSIONS)
#undef HAVE_JPEGTURBO
#endif
#endif

#if defined(HAVE_JPEGTURBO) && JPEG_LIB_VERSION < 80
/* Read JPEG image from a memory segment
 * - see http://stackoverflow.com/questions/5280756/libjpeg-ver-6b-jpeg-stdio-src-vs-jpeg-mem-src */

#include <jerror.h>

static void init_source (j_decompress_ptr cinfo)
{
}

static boolean fill_input_buffer (j_decompress_ptr cinfo)
{
    ERREXIT(cinfo, JERR_INPUT_EMPTY);
    return TRUE;
}

static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
    struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src;

    if (num_bytes > 0) {
        src->next_input_byte += (size_t) num_bytes;
        src->bytes_in_buffer -= (size_t) num_bytes;
    }
}

static void term_source (j_decompress_ptr cinfo)
{
}

static void jpeg_mem_src (j_decompress_ptr cinfo, void* buffer, long nbytes)
{
    struct jpeg_source_mgr* src;

    if (cinfo->src == NULL) {   /* first time for this JPEG object? */
        cinfo->src = (struct jpeg_source_mgr *)
            (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
                    sizeof(struct jpeg_source_mgr));
    }

    src = (struct jpeg_source_mgr*) cinfo->src;
    src->init_source = init_source;
    src->fill_input_buffer = fill_input_buffer;
    src->skip_input_data = skip_input_data;
    src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
    src->term_source = term_source;
    src->bytes_in_buffer = nbytes;
    src->next_input_byte = (JOCTET*)buffer;
}
#endif

#ifdef HAVE_JPEGTURBO

#include <assert.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdexcept>

#ifdef _MSC_VER
#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
#pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
#endif

namespace
{

// Error handler object
struct JPEGErrorManager
{
    // Error handler object
    jpeg_error_mgr pub;
    // setjmp buffer
    jmp_buf jmpbuf;
};

static void JPEGErrorExit(j_common_ptr info)
{
    JPEGErrorManager* err = (JPEGErrorManager*)info->err;

    //fprintf(stderr, "JPEG error %d: \"%s\"\n",
    //    err->pub.msg_code, err->pub.jpeg_message_table[err->pub.msg_code]);

    longjmp(err->jmpbuf, 1);
}

static J_COLOR_SPACE JPEGGetColorSpace(virvo::PixelFormat format)
{
    switch (format)
    {
    case virvo::PF_R8:
    case virvo::PF_LUMINANCE8:
        return JCS_GRAYSCALE;
    case virvo::PF_RGB8:
        return JCS_EXT_RGB;
    case virvo::PF_RGBA8:
        return JCS_EXT_RGBA;
    case virvo::PF_BGR8:
        return JCS_EXT_BGR;
    case virvo::PF_BGRA8:
        return JCS_EXT_BGRA;
    default:
        return JCS_UNKNOWN;
    }
}

struct JPEGDecodeCleanup
{
    jpeg_decompress_struct* info;

    JPEGDecodeCleanup() : info(0)
    {
    }

    ~JPEGDecodeCleanup()
    {
        if (info)
        {
            jpeg_finish_decompress(info); // Finish decompression
            jpeg_destroy_decompress(info); // Destroy the JPEG decompression object
        }
    }
};

struct JPEGEncodeCleanup
{
    jpeg_compress_struct* info;

    JPEGEncodeCleanup() : info(0)
    {
    }

    ~JPEGEncodeCleanup()
    {
        if (info)
        {
            jpeg_finish_compress(info);
            jpeg_destroy_compress(info);
        }
    }
};

// Encode a raw image into a std::vector
struct JPEGDestinationManager : jpeg_destination_mgr
{
    std::vector<unsigned char>& buffer;

    JPEGDestinationManager(std::vector<unsigned char>& buffer) : buffer(buffer)
    {
        this->init_destination = &InitDestination;
        this->empty_output_buffer = &EmptyOutputBuffer;
        this->term_destination = &TermDestination;
    }

    static void InitDestination(j_compress_ptr cinfo)
    {
        JPEGDestinationManager* dest = (JPEGDestinationManager*)cinfo->dest;

        dest->buffer.resize(16 * 1024);

        dest->next_output_byte = &dest->buffer[0];
        dest->free_in_buffer = dest->buffer.size();
    }

    static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
    {
        JPEGDestinationManager* dest = (JPEGDestinationManager*)cinfo->dest;

        size_t size = dest->buffer.size();

        dest->buffer.resize(size * 2);

        dest->next_output_byte = &dest->buffer[size];
        dest->free_in_buffer = dest->buffer.size() - size;

        return TRUE;
    }

    static void TermDestination(j_compress_ptr cinfo)
    {
        JPEGDestinationManager* dest = (JPEGDestinationManager*)cinfo->dest;

        dest->buffer.resize(dest->buffer.size() - dest->free_in_buffer);
    }
};

} // namespace

bool virvo::encodeJPEG(std::vector<unsigned char>& data, JPEGOptions const& options)
{
    J_COLOR_SPACE colorSpace = JPEGGetColorSpace(options.format);

    if (colorSpace == JCS_UNKNOWN)
        return false;

    // Get the pixel format of the uncompressed image
    virvo::PixelFormatInfo imageFormat = mapPixelFormat(options.format);

    // Destination buffer
    std::vector<unsigned char> compressed;

    // Master record for a compression instance
    jpeg_compress_struct info;
    // Error handler object
    JPEGErrorManager err;
    // Data destination object for compression
    JPEGDestinationManager dest(compressed);
    // RAII Clean up
    JPEGEncodeCleanup cleanup;

    //
    // Initialize error-management
    //

    info.err = jpeg_std_error(&err.pub);

    err.pub.error_exit = &JPEGErrorExit;

    //
    // NOTE:
    //
    // All objects need to be fully constructed before this line, so these objects
    // get destructed properly when an error occurs.
    //
    if (setjmp(err.jmpbuf))
    {
        return false;
    }

    //
    // Initialize a JPEG decompression object.
    //

    jpeg_create_compress(&info);

    cleanup.info = &info;

    //
    // Specify the destination of the compressed data
    //

    info.dest = &dest;

    //
    // Set image parameters
    //

    info.image_width = options.w;
    info.image_height = options.h;

    //
    // Set parameters for compression
    //

    info.input_components = imageFormat.components;
    info.in_color_space = colorSpace;

    jpeg_set_defaults(&info);
    jpeg_set_quality(&info, options.quality, TRUE);

    //
    // Start decompression
    //

    jpeg_start_compress(&info, TRUE);

    //
    // Compress the image
    //

    while (info.next_scanline < info.image_height)
    {
        unsigned char* row = &data[0] + info.next_scanline * options.pitch;

        jpeg_write_scanlines(&info, &row, 1);
    }

    //
    // Success!
    //

    data.swap(compressed);

    return true;
}

bool virvo::decodeJPEG(std::vector<unsigned char>& data, JPEGOptions& options)
{
    J_COLOR_SPACE colorSpace = JPEGGetColorSpace(options.format);

    if (colorSpace == JCS_UNKNOWN)
        return false;

    // Get the pixel format of the uncompressed image
    virvo::PixelFormatInfo imageFormat = mapPixelFormat(options.format);

    // Destination buffer
    std::vector<unsigned char> uncompressed;

    // Master record for a decompression instance
    jpeg_decompress_struct info;
    // Error handler object
    JPEGErrorManager err;
    // RAII Clean up
    JPEGDecodeCleanup cleanup;

    //
    // Initialize error-management
    //

    info.err = jpeg_std_error(&err.pub);

    err.pub.error_exit = &JPEGErrorExit;

    //
    // NOTE:
    //
    // All objects need to be fully constructed before this line, so these objects
    // get destructed properly when an error occurs.
    //
    if (setjmp(err.jmpbuf))
    {
        return false;
    }

    //
    // Initialize a JPEG decompression object.
    //

    jpeg_create_decompress(&info);

    cleanup.info = &info;

    //
    // Specify the source of the compressed data
    //

    jpeg_mem_src(&info, &data[0], (unsigned long)data.size());

    //
    // Read image parameters
    //

    jpeg_read_header(&info, TRUE);

    options.w = info.image_width;
    options.h = info.image_height;
    options.pitch = options.w * imageFormat.size;

    //
    // Set parameters for decompression
    //

    info.out_color_components = imageFormat.components;
    info.out_color_space = colorSpace;

    // prefer speed...
    info.do_block_smoothing = 0;
    info.do_fancy_upsampling = 0;

    //
    // Start decompression
    //

    jpeg_start_decompress(&info);

    //
    // Decompress the image
    //

    uncompressed.resize(options.pitch * options.h);

    while (info.output_scanline < info.output_height)
    {
        unsigned char* row = &uncompressed[0] + info.output_scanline * options.pitch;

        jpeg_read_scanlines(&info, &row, 1);
    }

    //
    // Success!
    //

    data.swap(uncompressed);

    return true;
}

#else // HAVE_JPEGTURBO

bool virvo::encodeJPEG(std::vector<unsigned char>& /*data*/, JPEGOptions const& /*options*/)
{
    return false;
}

bool virvo::decodeJPEG(std::vector<unsigned char>& /*data*/, JPEGOptions& /*options*/)
{
    return false;
}

#endif // !HAVE_JPEGTURBO

bool virvo::encodeJPEG(CompressedVector& data, JPEGOptions const& options)
{
    if (data.getCompressionType() != Compress_None)
        return false;

    if (encodeJPEG(data.vector(), options))
    {
        data.setCompressionType(Compress_JPEG);
        return true;
    }

    return false;
}

bool virvo::decodeJPEG(CompressedVector& data, JPEGOptions& options)
{
    if (data.getCompressionType() != Compress_JPEG)
        return false;

    if (decodeJPEG(data.vector(), options))
    {
        data.setCompressionType(Compress_None);
        return true;
    }

    return false;
}
<commit_msg>Check if jpeg_src_mem is already implemented using MEM_SRCDST_SUPPORTED<commit_after>// Virvo - Virtual Reality Volume Rendering
// Copyright (C) 1999-2003 University of Stuttgart, 2004-2005 Brown University
// Contact: Jurgen P. Schulze, jschulze@ucsd.edu
//
// This file is part of Virvo.
//
// Virvo is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library (see license.txt); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include "vvcompress.h"
#include "vvcompressedvector.h"

#ifdef HAVE_CONFIG_H
#include "vvconfig.h"
#endif

#ifdef HAVE_JPEGTURBO
#include <stdio.h>
#include <jpeglib.h>
#if !defined(LIBJPEG_TURBO_VERSION)
#undef HAVE_JPEGTURBO
#endif
#if !defined(JCS_EXTENSIONS) || !defined(JCS_ALPHA_EXTENSIONS)
#undef HAVE_JPEGTURBO
#endif
#endif

#if defined(HAVE_JPEGTURBO) && !(JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED))
/* Read JPEG image from a memory segment
 * - see http://stackoverflow.com/questions/5280756/libjpeg-ver-6b-jpeg-stdio-src-vs-jpeg-mem-src */

#include <jerror.h>

static void init_source (j_decompress_ptr /*cinfo*/)
{
}

static boolean fill_input_buffer (j_decompress_ptr cinfo)
{
    ERREXIT(cinfo, JERR_INPUT_EMPTY);
    return TRUE;
}

static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
    struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src;

    if (num_bytes > 0) {
        src->next_input_byte += (size_t) num_bytes;
        src->bytes_in_buffer -= (size_t) num_bytes;
    }
}

static void term_source (j_decompress_ptr /*cinfo*/)
{
}

static void jpeg_mem_src (j_decompress_ptr cinfo, unsigned char* buffer, unsigned long nbytes)
{
    struct jpeg_source_mgr* src;

    if (cinfo->src == NULL) {   /* first time for this JPEG object? */
        cinfo->src = (struct jpeg_source_mgr *)
            (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
                    sizeof(struct jpeg_source_mgr));
    }

    src = (struct jpeg_source_mgr*) cinfo->src;
    src->init_source = init_source;
    src->fill_input_buffer = fill_input_buffer;
    src->skip_input_data = skip_input_data;
    src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
    src->term_source = term_source;
    src->bytes_in_buffer = (size_t)nbytes;
    src->next_input_byte = (JOCTET*)buffer;
}

#endif

#ifdef HAVE_JPEGTURBO

#include <assert.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdexcept>

#ifdef _MSC_VER
#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
#pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
#endif

namespace
{

// Error handler object
struct JPEGErrorManager
{
    // Error handler object
    jpeg_error_mgr pub;
    // setjmp buffer
    jmp_buf jmpbuf;
};

static void JPEGErrorExit(j_common_ptr info)
{
    JPEGErrorManager* err = (JPEGErrorManager*)info->err;

    //fprintf(stderr, "JPEG error %d: \"%s\"\n",
    //    err->pub.msg_code, err->pub.jpeg_message_table[err->pub.msg_code]);

    longjmp(err->jmpbuf, 1);
}

static J_COLOR_SPACE JPEGGetColorSpace(virvo::PixelFormat format)
{
    switch (format)
    {
    case virvo::PF_R8:
    case virvo::PF_LUMINANCE8:
        return JCS_GRAYSCALE;
    case virvo::PF_RGB8:
        return JCS_EXT_RGB;
    case virvo::PF_RGBA8:
        return JCS_EXT_RGBA;
    case virvo::PF_BGR8:
        return JCS_EXT_BGR;
    case virvo::PF_BGRA8:
        return JCS_EXT_BGRA;
    default:
        return JCS_UNKNOWN;
    }
}

struct JPEGDecodeCleanup
{
    jpeg_decompress_struct* info;

    JPEGDecodeCleanup() : info(0)
    {
    }

    ~JPEGDecodeCleanup()
    {
        if (info)
        {
            jpeg_finish_decompress(info); // Finish decompression
            jpeg_destroy_decompress(info); // Destroy the JPEG decompression object
        }
    }
};

struct JPEGEncodeCleanup
{
    jpeg_compress_struct* info;

    JPEGEncodeCleanup() : info(0)
    {
    }

    ~JPEGEncodeCleanup()
    {
        if (info)
        {
            jpeg_finish_compress(info);
            jpeg_destroy_compress(info);
        }
    }
};

// Encode a raw image into a std::vector
struct JPEGDestinationManager : jpeg_destination_mgr
{
    std::vector<unsigned char>& buffer;

    JPEGDestinationManager(std::vector<unsigned char>& buffer) : buffer(buffer)
    {
        this->init_destination = &InitDestination;
        this->empty_output_buffer = &EmptyOutputBuffer;
        this->term_destination = &TermDestination;
    }

    static void InitDestination(j_compress_ptr cinfo)
    {
        JPEGDestinationManager* dest = (JPEGDestinationManager*)cinfo->dest;

        dest->buffer.resize(16 * 1024);

        dest->next_output_byte = &dest->buffer[0];
        dest->free_in_buffer = dest->buffer.size();
    }

    static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
    {
        JPEGDestinationManager* dest = (JPEGDestinationManager*)cinfo->dest;

        size_t size = dest->buffer.size();

        dest->buffer.resize(size * 2);

        dest->next_output_byte = &dest->buffer[size];
        dest->free_in_buffer = dest->buffer.size() - size;

        return TRUE;
    }

    static void TermDestination(j_compress_ptr cinfo)
    {
        JPEGDestinationManager* dest = (JPEGDestinationManager*)cinfo->dest;

        dest->buffer.resize(dest->buffer.size() - dest->free_in_buffer);
    }
};

} // namespace

bool virvo::encodeJPEG(std::vector<unsigned char>& data, JPEGOptions const& options)
{
    J_COLOR_SPACE colorSpace = JPEGGetColorSpace(options.format);

    if (colorSpace == JCS_UNKNOWN)
        return false;

    // Get the pixel format of the uncompressed image
    virvo::PixelFormatInfo imageFormat = mapPixelFormat(options.format);

    // Destination buffer
    std::vector<unsigned char> compressed;

    // Master record for a compression instance
    jpeg_compress_struct info;
    // Error handler object
    JPEGErrorManager err;
    // Data destination object for compression
    JPEGDestinationManager dest(compressed);
    // RAII Clean up
    JPEGEncodeCleanup cleanup;

    //
    // Initialize error-management
    //

    info.err = jpeg_std_error(&err.pub);

    err.pub.error_exit = &JPEGErrorExit;

    //
    // NOTE:
    //
    // All objects need to be fully constructed before this line, so these objects
    // get destructed properly when an error occurs.
    //
    if (setjmp(err.jmpbuf))
    {
        return false;
    }

    //
    // Initialize a JPEG decompression object.
    //

    jpeg_create_compress(&info);

    cleanup.info = &info;

    //
    // Specify the destination of the compressed data
    //

    info.dest = &dest;

    //
    // Set image parameters
    //

    info.image_width = options.w;
    info.image_height = options.h;

    //
    // Set parameters for compression
    //

    info.input_components = imageFormat.components;
    info.in_color_space = colorSpace;

    jpeg_set_defaults(&info);
    jpeg_set_quality(&info, options.quality, TRUE);

    //
    // Start decompression
    //

    jpeg_start_compress(&info, TRUE);

    //
    // Compress the image
    //

    while (info.next_scanline < info.image_height)
    {
        unsigned char* row = &data[0] + info.next_scanline * options.pitch;

        jpeg_write_scanlines(&info, &row, 1);
    }

    //
    // Success!
    //

    data.swap(compressed);

    return true;
}

bool virvo::decodeJPEG(std::vector<unsigned char>& data, JPEGOptions& options)
{
    J_COLOR_SPACE colorSpace = JPEGGetColorSpace(options.format);

    if (colorSpace == JCS_UNKNOWN)
        return false;

    // Get the pixel format of the uncompressed image
    virvo::PixelFormatInfo imageFormat = mapPixelFormat(options.format);

    // Destination buffer
    std::vector<unsigned char> uncompressed;

    // Master record for a decompression instance
    jpeg_decompress_struct info;
    // Error handler object
    JPEGErrorManager err;
    // RAII Clean up
    JPEGDecodeCleanup cleanup;

    //
    // Initialize error-management
    //

    info.err = jpeg_std_error(&err.pub);

    err.pub.error_exit = &JPEGErrorExit;

    //
    // NOTE:
    //
    // All objects need to be fully constructed before this line, so these objects
    // get destructed properly when an error occurs.
    //
    if (setjmp(err.jmpbuf))
    {
        return false;
    }

    //
    // Initialize a JPEG decompression object.
    //

    jpeg_create_decompress(&info);

    cleanup.info = &info;

    //
    // Specify the source of the compressed data
    //

    jpeg_mem_src(&info, &data[0], (unsigned long)data.size());

    //
    // Read image parameters
    //

    jpeg_read_header(&info, TRUE);

    options.w = info.image_width;
    options.h = info.image_height;
    options.pitch = options.w * imageFormat.size;

    //
    // Set parameters for decompression
    //

    info.out_color_components = imageFormat.components;
    info.out_color_space = colorSpace;

    // prefer speed...
    info.do_block_smoothing = 0;
    info.do_fancy_upsampling = 0;

    //
    // Start decompression
    //

    jpeg_start_decompress(&info);

    //
    // Decompress the image
    //

    uncompressed.resize(options.pitch * options.h);

    while (info.output_scanline < info.output_height)
    {
        unsigned char* row = &uncompressed[0] + info.output_scanline * options.pitch;

        jpeg_read_scanlines(&info, &row, 1);
    }

    //
    // Success!
    //

    data.swap(uncompressed);

    return true;
}

#else // HAVE_JPEGTURBO

bool virvo::encodeJPEG(std::vector<unsigned char>& /*data*/, JPEGOptions const& /*options*/)
{
    return false;
}

bool virvo::decodeJPEG(std::vector<unsigned char>& /*data*/, JPEGOptions& /*options*/)
{
    return false;
}

#endif // !HAVE_JPEGTURBO

bool virvo::encodeJPEG(CompressedVector& data, JPEGOptions const& options)
{
    if (data.getCompressionType() != Compress_None)
        return false;

    if (encodeJPEG(data.vector(), options))
    {
        data.setCompressionType(Compress_JPEG);
        return true;
    }

    return false;
}

bool virvo::decodeJPEG(CompressedVector& data, JPEGOptions& options)
{
    if (data.getCompressionType() != Compress_JPEG)
        return false;

    if (decodeJPEG(data.vector(), options))
    {
        data.setCompressionType(Compress_None);
        return true;
    }

    return false;
}
<|endoftext|>


<commit_before>#include "Tracker.hpp"

#include <stdexcept>
#include <iostream>
#include <stdlib.h>

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <cvblob.h>

#include <ros/console.h>
#include <cmath>

#include "profiling.hpp"

// Use this to use the register keyword in some places. Might make things faster, but I didn't test it.
//#define QC_REGISTER

// Use this for debugging the object recognition. WARNING: Might lead to errors or strange behaviour when used with visualTracker == true.
//#define QC_DEBUG_TRACKER

Tracker::Tracker(ITrackerDataReceiver* dataReceiver, QuadcopterColor* color)
{
	this->dataReceiver = dataReceiver;
	this->thread = 0;
	this->image = 0;
	this->qc = color;

	this->showCameraImage = false;
	this->showMaskedImage = false;
}

Tracker::Tracker(ITrackerDataReceiver* dataReceiver, QuadcopterColor* color, bool showCameraImage, bool showMaskedImage)
{
	this->dataReceiver = dataReceiver;
	this->thread = 0;
	this->image = 0;
	this->qc = color;

	this->showCameraImage = showCameraImage;
	this->showMaskedImage = showMaskedImage;

	if (showMaskedImage) {
		std::stringstream ss;
		ss << "Tracker of id " << ((QuadcopterColor*) this->qc)->getId() << " showing masked image";

		this->maskedWindowName = ss.str();
		cv::startWindowThread();
	}

	if (showCameraImage) {
		std::stringstream ss;
		ss << "Tracker of id " << ((QuadcopterColor*) this->qc)->getId() << " showing camera image";

		this->cameraWindowName = ss.str();
		cv::startWindowThread();
	}
}

Tracker::~Tracker()
{
}

void Tracker::start()
{
	if (thread != 0) {
		throw new std::runtime_error("Already started. (Maybe you forgot to call join?)");
	}

	if (showMaskedImage) {
		cv::namedWindow(maskedWindowName);
	}

	if (showCameraImage) {
		cv::namedWindow(cameraWindowName);
	}

	imageDirty = 0;
	stopFlag = false;

	thread = new boost::thread(boost::bind(&Tracker::executeTracker, this));
}

void Tracker::stop()
{
	if (thread == 0) {
		throw new std::runtime_error("Not started.");
	}

	stopFlag = true;
}

void Tracker::join()
{
	if (thread != 0) {
		thread->join();
		delete thread;
		thread = 0;
	}

	if (this->image != 0) {
		delete this->image;
		this->image = 0;
	}
}

bool Tracker::isStarted()
{
	return thread != 0;
}

void Tracker::setNextImage(cv::Mat* image, long int time)
{
	imageMutex.lock();

	if (this->image != 0) {
		delete this->image;
	}

	this->image = new cv::Mat(*image);
	imageTime = time;
	imageDirty++;

	imageMutex.unlock();
}

QuadcopterColor* Tracker::getQuadcopterColor()
{
	return (QuadcopterColor*) qc;
}

void Tracker::drawCross(cv::Mat* mat, const int x, const int y)
{
	ROS_DEBUG("Drawing cross.");

	for (int i = x - 10; i <= x + 10; i++) {
		int j = y;

// 		ROS_DEBUG("i/j: %d/%d", i, j);
		if (i >= 0 && i < mat->rows && j >= 0 && j < mat->cols) {
			unsigned char* element = mat->data + mat->step[0] * j + mat->step[1] * i;

			unsigned char color;

			if (i + j % 3 > 0) {
				color = 0xFF;
			} else {
				color = 0;
			}

			element[0] = color;
			element[1] = color;
			element[2] = color;
		}
	}

	for (int j = y - 10; j <= y + 10; j++) {
		int i = x;

// 		ROS_DEBUG("i/j: %d/%d", i, j);
		if (i >= 0 && i < mat->rows && j >= 0 && j < mat->cols) {
			unsigned char* element = mat->data + mat->step[0] * j + mat->step[1] * i;

			unsigned char color;

			if (i + j % 3 > 0) {
				color = 0xFF;
			} else {
				color = 0;
			}

			element[0] = color;
			element[1] = color;
			element[2] = color;
		}
	}

	ROS_DEBUG("Cross drawed");
}

void Tracker::executeTracker()
{
	#ifdef QC_DEBUG_TRACKER
	cv::startWindowThread();
	cv::namedWindow("Tracker");
	#endif

	#define PI (3.1415926535897932384626433832795028841)
	// Kinect fow: 43° vertical, 57° horizontal
	double verticalScalingFactor = tan(43 * PI / 180) / 240;
	double horizontalScalingFactor = tan(57 * PI / 180) / 320;
	ROS_DEBUG("Scaling factors: %lf/%lf", horizontalScalingFactor, verticalScalingFactor);

	bool quadcopterTracked = false;

	while (!stopFlag) {
		if (imageDirty == 0) {
			usleep(100);
			continue;
		} else if (imageDirty > 1) {
			ROS_WARN("Skipped %d frames!", imageDirty - 1);
		}

		START_CLOCK(trackerClock)

		imageMutex.lock();
		cv::Mat* image = (cv::Mat*) this->image;
		image = new cv::Mat(*image);
		long int time = this->imageTime;
		imageDirty = 0;
		imageMutex.unlock();

		cv::Mat* cameraImage = 0;
		cv::Mat* maskedImage = 0;

		if (showCameraImage) {
			cameraImage = new cv::Mat(image->size(), image->type());
			image->copyTo(*cameraImage);
		}

		#ifdef QC_DEBUG_TRACKER
		cv::imshow("Tracker", *image);
		cv::waitKey(100000);
		#endif

		cv::Mat* mapImage = createColorMapImage(image);

		if (showMaskedImage) {
			// Convert to 3 channel image.
			maskedImage = new cv::Mat(cv::Size(640, 480), CV_8UC3);
			int target = 0;

			for (int i = 0; i < mapImage->total(); ++i) {
				maskedImage->data[target++] = mapImage->data[i];
				maskedImage->data[target++] = mapImage->data[i];
				maskedImage->data[target++] = mapImage->data[i];
			}
		}

		#ifdef QC_DEBUG_TRACKER
		cv::imshow("Tracker", *mapImage);
		cv::waitKey(100000);
		#endif

		cv::Mat morphKernel = cv::getStructuringElement(CV_SHAPE_RECT, cv::Size(5, 5));
		cv::morphologyEx(*mapImage, *mapImage, cv::MORPH_OPEN, morphKernel);

		// Finding blobs
		cvb::CvBlobs blobs;
		IplImage *labelImg = cvCreateImage(image->size(), IPL_DEPTH_LABEL, 1);
		IplImage iplMapImage = *mapImage;
		unsigned int result = cvLabel(&iplMapImage, labelImg, blobs);
		// ROS_DEBUG("Blob result: %d", result);

		// Filter blobs
		cvFilterByArea(blobs, 10, 1000000);

		#ifdef QC_DEBUG_TRACKER
		IplImage iplImage = *image;
		cvRenderBlobs(labelImg, blobs, &iplImage, &iplImage, CV_BLOB_RENDER_BOUNDING_BOX);
		cvb::CvTracks tracks;
		cvUpdateTracks(blobs, tracks, 200., 5);
		cvRenderTracks(tracks, &iplImage, &iplImage, CV_TRACK_RENDER_ID | CV_TRACK_RENDER_BOUNDING_BOX);
		cv::imshow("Tracker", cv::Mat(&iplImage));
		cv::waitKey(100000);
		cvReleaseTracks(tracks);
		ROS_DEBUG("Exiting debug block"); // TODO Tracking down issue #7
		#endif

		cvb::CvTracks tracks;

		if (showCameraImage || showMaskedImage) {
			cvUpdateTracks(blobs, tracks, 200., 5);
		}

		if (showMaskedImage) {
			IplImage iplImage = *maskedImage;
			cvRenderBlobs(labelImg, blobs, &iplImage, &iplImage, CV_BLOB_RENDER_BOUNDING_BOX);
			cvRenderTracks(tracks, &iplImage, &iplImage, CV_TRACK_RENDER_ID | CV_TRACK_RENDER_BOUNDING_BOX);
			ROS_DEBUG("Exiting visual masked block"); // TODO Tracking down issue #7
		}

		if (showCameraImage) {
			IplImage iplImage = *cameraImage;
			cvRenderBlobs(labelImg, blobs, &iplImage, &iplImage, CV_BLOB_RENDER_BOUNDING_BOX);
			cvRenderTracks(tracks, &iplImage, &iplImage, CV_TRACK_RENDER_ID | CV_TRACK_RENDER_BOUNDING_BOX);
			ROS_DEBUG("Exiting visual masked block"); // TODO Tracking down issue #7
		}

		if (showCameraImage || showMaskedImage) {
			cvReleaseTracks(tracks);
		}

		if (blobs.size() != 0) {
			// Find biggest blob
			cvb::CvLabel largestBlob =  cvLargestBlob(blobs);
			CvPoint2D64f center = blobs.find(largestBlob)->second->centroid;
			double x = center.x;
			double y = center.y;

			// Set (0, 0) to center.
			x -= 320;
			y -= 240;
			//ROS_DEBUG("Center: %lf/%lf", x, y);

			// Apply scaling
			x *= horizontalScalingFactor;
			y *= verticalScalingFactor;

			dataReceiver->receiveTrackingData(cv::Scalar(x, y, 1.0), ((QuadcopterColor*) qc)->getId(), time);

			if (showMaskedImage) {
				drawCross(maskedImage, center.x, center.y);
			}

			if (showCameraImage) {
				drawCross(cameraImage, center.x, center.y);
			}

			if (!quadcopterTracked) {
				quadcopterTracked = true;
				ROS_DEBUG("Quadcopter tracked");
			}
		} else if (quadcopterTracked) {
			quadcopterTracked = false;
			ROS_DEBUG("Quadcopter NOT tracked");
		}

		// Free cvb stuff.
		cvReleaseBlobs(blobs);
		cvReleaseImage(&labelImg);

		// ROS_DEBUG("cvb stuff freed"); // TODO Tracking down issue #7

		if (showMaskedImage) {
			cv::imshow(maskedWindowName, *maskedImage);
			delete maskedImage;

			ROS_DEBUG("showed masked image"); // TODO Tracking down issue #7
		}

		if (showCameraImage) {
			cv::imshow(cameraWindowName, *cameraImage);
			delete cameraImage;

			ROS_DEBUG("showed camera image"); // TODO Tracking down issue #7
		}

		delete mapImage;
		delete image;

		STOP_CLOCK(trackerClock, "Calculation of quadcopter position took: ")
	}

	#ifdef QC_DEBUG_TRACKER
	cv::destroyWindow("Tracker");
	#endif

	if (showMaskedImage) {
		cv::destroyWindow(maskedWindowName);
	}

	if (showCameraImage) {
		cv::destroyWindow(cameraWindowName);
	}

	ROS_INFO("Tracker with id %d terminated", ((QuadcopterColor*) this->qc)->getId());
}

cv::Mat* Tracker::createColorMapImage(cv::Mat* image) {
	START_CLOCK(convertColorClock)

	cv::Mat* mapImage = new cv::Mat(image->size(), CV_8UC1);

	// Debug HSV color range
	// unsigned char* element = image->data + image->step[0] * 240 + image->step[1] * 320;
	// ROS_DEBUG("R: %d G: %d B: %d", element[2], element[1], element[0]);

	cv::cvtColor(*image, *image, CV_BGR2HSV);

	// Debug HSV color range
	// ROS_DEBUG("H: %d S: %d V: %d", element[0], element[1], element[2]);

	STOP_CLOCK(convertColorClock, "Converting colors took: ")
	START_CLOCK(maskImageClock)

	// Trying to make this fast.
	#ifdef QC_REGISTER
	register uint8_t *current, *end, *source;
	register int minHue, maxHue, minSaturation, /*maxSaturation,*/ minValue/*, maxValue*/;
	#else
	uint8_t *current, *end, *source;
	int minHue, maxHue, minSaturation, /*maxSaturation,*/ minValue/*, maxValue*/;
	#endif

	QuadcopterColor* color = (QuadcopterColor*) qc;

	minHue = color->getMinColor().val[0];
	maxHue = color->getMaxColor().val[0];
	minSaturation = color->getMinColor().val[1];
	//maxSaturation = color->getMaxColor().val[1]; // unused
	minValue = color->getMinColor().val[2];
	//maxValue = color->getMaxColor().val[2]; // unused

	end = mapImage->data + mapImage->size().width * mapImage->size().height;
	source = image->data;

	if (minHue < maxHue) {
		for (current = mapImage->data; current < end; ++current, source += 3) {
			//if (*source > maxHue || *source < minHue || *(++source) > maxSaturation || *source < minSaturation || *(++source) > maxValue || *(source++) < minValue) {
			if (*source > maxHue || *source < minHue || *(source + 1) < minSaturation || *(source + 2) < minValue) {
				*current = 0;
			} else {
				*current = 255;
			}
		}
	} else {
		// Hue interval inverted here.
		for (current = mapImage->data; current < end; ++current, source += 3) {
			//if (*source < maxHue || *source > minHue || *(++source) > maxSaturation || *source < minSaturation || *(++source) > maxValue || *(source++) < minValue) {
			if ((*source > maxHue && *source < minHue) || *(source + 1) < minSaturation || *(source + 2) < minValue) {
				*current = 0;
			} else {
				*current = 255;
			}
		}
	}

	STOP_CLOCK(maskImageClock, "Image masking took: ")

	return mapImage;
}
<commit_msg>Reduced minimum amount of pixels to recognize the tracking marker<commit_after>#include "Tracker.hpp"

#include <stdexcept>
#include <iostream>
#include <stdlib.h>

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <cvblob.h>

#include <ros/console.h>
#include <cmath>

#include "profiling.hpp"

// Use this to use the register keyword in some places. Might make things faster, but I didn't test it.
//#define QC_REGISTER

// Use this for debugging the object recognition. WARNING: Might lead to errors or strange behaviour when used with visualTracker == true.
//#define QC_DEBUG_TRACKER

Tracker::Tracker(ITrackerDataReceiver* dataReceiver, QuadcopterColor* color)
{
	this->dataReceiver = dataReceiver;
	this->thread = 0;
	this->image = 0;
	this->qc = color;

	this->showCameraImage = false;
	this->showMaskedImage = false;
}

Tracker::Tracker(ITrackerDataReceiver* dataReceiver, QuadcopterColor* color, bool showCameraImage, bool showMaskedImage)
{
	this->dataReceiver = dataReceiver;
	this->thread = 0;
	this->image = 0;
	this->qc = color;

	this->showCameraImage = showCameraImage;
	this->showMaskedImage = showMaskedImage;

	if (showMaskedImage) {
		std::stringstream ss;
		ss << "Tracker of id " << ((QuadcopterColor*) this->qc)->getId() << " showing masked image";

		this->maskedWindowName = ss.str();
		cv::startWindowThread();
	}

	if (showCameraImage) {
		std::stringstream ss;
		ss << "Tracker of id " << ((QuadcopterColor*) this->qc)->getId() << " showing camera image";

		this->cameraWindowName = ss.str();
		cv::startWindowThread();
	}
}

Tracker::~Tracker()
{
}

void Tracker::start()
{
	if (thread != 0) {
		throw new std::runtime_error("Already started. (Maybe you forgot to call join?)");
	}

	if (showMaskedImage) {
		cv::namedWindow(maskedWindowName);
	}

	if (showCameraImage) {
		cv::namedWindow(cameraWindowName);
	}

	imageDirty = 0;
	stopFlag = false;

	thread = new boost::thread(boost::bind(&Tracker::executeTracker, this));
}

void Tracker::stop()
{
	if (thread == 0) {
		throw new std::runtime_error("Not started.");
	}

	stopFlag = true;
}

void Tracker::join()
{
	if (thread != 0) {
		thread->join();
		delete thread;
		thread = 0;
	}

	if (this->image != 0) {
		delete this->image;
		this->image = 0;
	}
}

bool Tracker::isStarted()
{
	return thread != 0;
}

void Tracker::setNextImage(cv::Mat* image, long int time)
{
	imageMutex.lock();

	if (this->image != 0) {
		delete this->image;
	}

	this->image = new cv::Mat(*image);
	imageTime = time;
	imageDirty++;

	imageMutex.unlock();
}

QuadcopterColor* Tracker::getQuadcopterColor()
{
	return (QuadcopterColor*) qc;
}

void Tracker::drawCross(cv::Mat* mat, const int x, const int y)
{
	ROS_DEBUG("Drawing cross.");

	for (int i = x - 10; i <= x + 10; i++) {
		int j = y;

// 		ROS_DEBUG("i/j: %d/%d", i, j);
		if (i >= 0 && i < mat->rows && j >= 0 && j < mat->cols) {
			unsigned char* element = mat->data + mat->step[0] * j + mat->step[1] * i;

			unsigned char color;

			if (i + j % 3 > 0) {
				color = 0xFF;
			} else {
				color = 0;
			}

			element[0] = color;
			element[1] = color;
			element[2] = color;
		}
	}

	for (int j = y - 10; j <= y + 10; j++) {
		int i = x;

// 		ROS_DEBUG("i/j: %d/%d", i, j);
		if (i >= 0 && i < mat->rows && j >= 0 && j < mat->cols) {
			unsigned char* element = mat->data + mat->step[0] * j + mat->step[1] * i;

			unsigned char color;

			if (i + j % 3 > 0) {
				color = 0xFF;
			} else {
				color = 0;
			}

			element[0] = color;
			element[1] = color;
			element[2] = color;
		}
	}

	ROS_DEBUG("Cross drawed");
}

void Tracker::executeTracker()
{
	#ifdef QC_DEBUG_TRACKER
	cv::startWindowThread();
	cv::namedWindow("Tracker");
	#endif

	#define PI (3.1415926535897932384626433832795028841)
	// Kinect fow: 43° vertical, 57° horizontal
	double verticalScalingFactor = tan(43 * PI / 180) / 240;
	double horizontalScalingFactor = tan(57 * PI / 180) / 320;
	ROS_DEBUG("Scaling factors: %lf/%lf", horizontalScalingFactor, verticalScalingFactor);

	bool quadcopterTracked = false;

	while (!stopFlag) {
		if (imageDirty == 0) {
			usleep(100);
			continue;
		} else if (imageDirty > 1) {
			ROS_WARN("Skipped %d frames!", imageDirty - 1);
		}

		START_CLOCK(trackerClock)

		imageMutex.lock();
		cv::Mat* image = (cv::Mat*) this->image;
		image = new cv::Mat(*image);
		long int time = this->imageTime;
		imageDirty = 0;
		imageMutex.unlock();

		cv::Mat* cameraImage = 0;
		cv::Mat* maskedImage = 0;

		if (showCameraImage) {
			cameraImage = new cv::Mat(image->size(), image->type());
			image->copyTo(*cameraImage);
		}

		#ifdef QC_DEBUG_TRACKER
		cv::imshow("Tracker", *image);
		cv::waitKey(100000);
		#endif

		cv::Mat* mapImage = createColorMapImage(image);

		if (showMaskedImage) {
			// Convert to 3 channel image.
			maskedImage = new cv::Mat(cv::Size(640, 480), CV_8UC3);
			int target = 0;

			for (int i = 0; i < mapImage->total(); ++i) {
				maskedImage->data[target++] = mapImage->data[i];
				maskedImage->data[target++] = mapImage->data[i];
				maskedImage->data[target++] = mapImage->data[i];
			}
		}

		#ifdef QC_DEBUG_TRACKER
		cv::imshow("Tracker", *mapImage);
		cv::waitKey(100000);
		#endif

		cv::Mat morphKernel = cv::getStructuringElement(CV_SHAPE_RECT, cv::Size(5, 5));
		cv::morphologyEx(*mapImage, *mapImage, cv::MORPH_OPEN, morphKernel);

		// Finding blobs
		cvb::CvBlobs blobs;
		IplImage *labelImg = cvCreateImage(image->size(), IPL_DEPTH_LABEL, 1);
		IplImage iplMapImage = *mapImage;
		unsigned int result = cvLabel(&iplMapImage, labelImg, blobs);
		// ROS_DEBUG("Blob result: %d", result);

		// Filter blobs
		cvFilterByArea(blobs, 6, 1000000);

		#ifdef QC_DEBUG_TRACKER
		IplImage iplImage = *image;
		cvRenderBlobs(labelImg, blobs, &iplImage, &iplImage, CV_BLOB_RENDER_BOUNDING_BOX);
		cvb::CvTracks tracks;
		cvUpdateTracks(blobs, tracks, 200., 5);
		cvRenderTracks(tracks, &iplImage, &iplImage, CV_TRACK_RENDER_ID | CV_TRACK_RENDER_BOUNDING_BOX);
		cv::imshow("Tracker", cv::Mat(&iplImage));
		cv::waitKey(100000);
		cvReleaseTracks(tracks);
		ROS_DEBUG("Exiting debug block"); // TODO Tracking down issue #7
		#endif

		cvb::CvTracks tracks;

		if (showCameraImage || showMaskedImage) {
			cvUpdateTracks(blobs, tracks, 200., 5);
		}

		if (showMaskedImage) {
			IplImage iplImage = *maskedImage;
			cvRenderBlobs(labelImg, blobs, &iplImage, &iplImage, CV_BLOB_RENDER_BOUNDING_BOX);
			cvRenderTracks(tracks, &iplImage, &iplImage, CV_TRACK_RENDER_ID | CV_TRACK_RENDER_BOUNDING_BOX);
			ROS_DEBUG("Exiting visual masked block"); // TODO Tracking down issue #7
		}

		if (showCameraImage) {
			IplImage iplImage = *cameraImage;
			cvRenderBlobs(labelImg, blobs, &iplImage, &iplImage, CV_BLOB_RENDER_BOUNDING_BOX);
			cvRenderTracks(tracks, &iplImage, &iplImage, CV_TRACK_RENDER_ID | CV_TRACK_RENDER_BOUNDING_BOX);
			ROS_DEBUG("Exiting visual masked block"); // TODO Tracking down issue #7
		}

		if (showCameraImage || showMaskedImage) {
			cvReleaseTracks(tracks);
		}

		if (blobs.size() != 0) {
			// Find biggest blob
			cvb::CvLabel largestBlob =  cvLargestBlob(blobs);
			CvPoint2D64f center = blobs.find(largestBlob)->second->centroid;
			double x = center.x;
			double y = center.y;

			// Set (0, 0) to center.
			x -= 320;
			y -= 240;
			//ROS_DEBUG("Center: %lf/%lf", x, y);

			// Apply scaling
			x *= horizontalScalingFactor;
			y *= verticalScalingFactor;

			dataReceiver->receiveTrackingData(cv::Scalar(x, y, 1.0), ((QuadcopterColor*) qc)->getId(), time);

			if (showMaskedImage) {
				drawCross(maskedImage, center.x, center.y);
			}

			if (showCameraImage) {
				drawCross(cameraImage, center.x, center.y);
			}

			if (!quadcopterTracked) {
				quadcopterTracked = true;
				ROS_DEBUG("Quadcopter tracked");
			}
		} else if (quadcopterTracked) {
			quadcopterTracked = false;
			ROS_DEBUG("Quadcopter NOT tracked");
		}

		// Free cvb stuff.
		cvReleaseBlobs(blobs);
		cvReleaseImage(&labelImg);

		// ROS_DEBUG("cvb stuff freed"); // TODO Tracking down issue #7

		if (showMaskedImage) {
			cv::imshow(maskedWindowName, *maskedImage);
			delete maskedImage;

			ROS_DEBUG("showed masked image"); // TODO Tracking down issue #7
		}

		if (showCameraImage) {
			cv::imshow(cameraWindowName, *cameraImage);
			delete cameraImage;

			ROS_DEBUG("showed camera image"); // TODO Tracking down issue #7
		}

		delete mapImage;
		delete image;

		STOP_CLOCK(trackerClock, "Calculation of quadcopter position took: ")
	}

	#ifdef QC_DEBUG_TRACKER
	cv::destroyWindow("Tracker");
	#endif

	if (showMaskedImage) {
		cv::destroyWindow(maskedWindowName);
	}

	if (showCameraImage) {
		cv::destroyWindow(cameraWindowName);
	}

	ROS_INFO("Tracker with id %d terminated", ((QuadcopterColor*) this->qc)->getId());
}

cv::Mat* Tracker::createColorMapImage(cv::Mat* image) {
	START_CLOCK(convertColorClock)

	cv::Mat* mapImage = new cv::Mat(image->size(), CV_8UC1);

	// Debug HSV color range
	// unsigned char* element = image->data + image->step[0] * 240 + image->step[1] * 320;
	// ROS_DEBUG("R: %d G: %d B: %d", element[2], element[1], element[0]);

	cv::cvtColor(*image, *image, CV_BGR2HSV);

	// Debug HSV color range
	// ROS_DEBUG("H: %d S: %d V: %d", element[0], element[1], element[2]);

	STOP_CLOCK(convertColorClock, "Converting colors took: ")
	START_CLOCK(maskImageClock)

	// Trying to make this fast.
	#ifdef QC_REGISTER
	register uint8_t *current, *end, *source;
	register int minHue, maxHue, minSaturation, /*maxSaturation,*/ minValue/*, maxValue*/;
	#else
	uint8_t *current, *end, *source;
	int minHue, maxHue, minSaturation, /*maxSaturation,*/ minValue/*, maxValue*/;
	#endif

	QuadcopterColor* color = (QuadcopterColor*) qc;

	minHue = color->getMinColor().val[0];
	maxHue = color->getMaxColor().val[0];
	minSaturation = color->getMinColor().val[1];
	//maxSaturation = color->getMaxColor().val[1]; // unused
	minValue = color->getMinColor().val[2];
	//maxValue = color->getMaxColor().val[2]; // unused

	end = mapImage->data + mapImage->size().width * mapImage->size().height;
	source = image->data;

	if (minHue < maxHue) {
		for (current = mapImage->data; current < end; ++current, source += 3) {
			//if (*source > maxHue || *source < minHue || *(++source) > maxSaturation || *source < minSaturation || *(++source) > maxValue || *(source++) < minValue) {
			if (*source > maxHue || *source < minHue || *(source + 1) < minSaturation || *(source + 2) < minValue) {
				*current = 0;
			} else {
				*current = 255;
			}
		}
	} else {
		// Hue interval inverted here.
		for (current = mapImage->data; current < end; ++current, source += 3) {
			//if (*source < maxHue || *source > minHue || *(++source) > maxSaturation || *source < minSaturation || *(++source) > maxValue || *(source++) < minValue) {
			if ((*source > maxHue && *source < minHue) || *(source + 1) < minSaturation || *(source + 2) < minValue) {
				*current = 0;
			} else {
				*current = 255;
			}
		}
	}

	STOP_CLOCK(maskImageClock, "Image masking took: ")

	return mapImage;
}
<|endoftext|>


<commit_before>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2020 Ryo Suzuki
//	Copyright (c) 2016-2020 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once

namespace s3d
{
	template <class Tag>
	struct YesNo
	{
	private:

		bool m_yesNo;

		struct Helper
		{
			bool yesNo;
		};

	public:

		constexpr YesNo(Helper helper) noexcept
			: m_yesNo(helper.yesNo) {}

		[[nodiscard]]
		explicit constexpr operator bool() const noexcept
		{
			return m_yesNo;
		}

		static constexpr Helper Yes{ true };

		static constexpr Helper No{ false };
	};
}
<commit_msg>[共通] update YesNo<commit_after>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2020 Ryo Suzuki
//	Copyright (c) 2016-2020 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once
# include "Platform.hpp"

namespace s3d
{
	template <class Tag>
	struct YesNo
	{
	private:

		bool m_yesNo;

		struct Helper
		{
			bool yesNo;
		};

	public:

		SIV3D_NODISCARD_CXX20
		explicit constexpr YesNo(bool yesNo) noexcept
			: m_yesNo{ yesNo } {}

		SIV3D_NODISCARD_CXX20
		constexpr YesNo(Helper helper) noexcept
			: m_yesNo{ helper.yesNo } {}

		[[nodiscard]]
		explicit constexpr operator bool() const noexcept
		{
			return m_yesNo;
		}

		static constexpr Helper Yes{ true };

		static constexpr Helper No{ false };
	};
}
<|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 "drawingml/chart/titlecontext.hxx"

#include "drawingml/shapepropertiescontext.hxx"
#include "drawingml/textbodycontext.hxx"
#include "drawingml/chart/datasourcecontext.hxx"
#include "drawingml/chart/titlemodel.hxx"

#include "rtl/ustrbuf.hxx"
#include <osl/diagnose.h>

namespace oox {
namespace drawingml {
namespace chart {

using ::oox::core::ContextHandler2Helper;
using ::oox::core::ContextHandlerRef;

TextContext::TextContext( ContextHandler2Helper& rParent, TextModel& rModel ) :
    ContextBase< TextModel >( rParent, rModel )
{
}

TextContext::~TextContext()
{
}

ContextHandlerRef TextContext::onCreateContext( sal_Int32 nElement, const AttributeList& )
{
    // this context handler is used for <c:tx> and embedded <c:v> elements
    if( isCurrentElement( C_TOKEN( tx ) ) ) switch( nElement )
    {
        case C_TOKEN( rich ):
            return new TextBodyContext( *this, mrModel.mxTextBody.create() );

        case C_TOKEN( strRef ):
            OSL_ENSURE( !mrModel.mxDataSeq, "TextContext::onCreateContext - multiple data sequences" );
            return new StringSequenceContext( *this, mrModel.mxDataSeq.create() );

        case C_TOKEN( v ):
            OSL_ENSURE( !mrModel.mxDataSeq, "TextContext::onCreateContext - multiple data sequences" );
            return this;    // collect value in onCharacters()
    }
    return 0;
}

void TextContext::onCharacters( const OUString& rChars )
{
    if( isCurrentElement( C_TOKEN( v ) ) )
    {
        // Static text is stored as a single string formula token for Excel document.
        OUStringBuffer aBuf;
        aBuf.append('"').append(rChars).append('"');
        mrModel.mxDataSeq.create().maFormula = aBuf.makeStringAndClear();

        // Also store it as a single element type for non-Excel document.
        mrModel.mxDataSeq->maData[0] <<= rChars;
    }
}

TitleContext::TitleContext( ContextHandler2Helper& rParent, TitleModel& rModel ) :
    ContextBase< TitleModel >( rParent, rModel )
{
}

TitleContext::~TitleContext()
{
}

ContextHandlerRef TitleContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
{
    // this context handler is used for <c:title> only
    switch( nElement )
    {
        case C_TOKEN( layout ):
            return new LayoutContext( *this, mrModel.mxLayout.create() );

        case C_TOKEN( overlay ):
            // default is 'false', not 'true' as specified
            mrModel.mbOverlay = rAttribs.getBool( XML_val, false );
            return 0;

        case C_TOKEN( spPr ):
            return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() );

        case C_TOKEN( tx ):
            return new TextContext( *this, mrModel.mxText.create() );

        case C_TOKEN( txPr ):
            return new TextBodyContext( *this, mrModel.mxTextProp.create() );
    }
    return 0;
}

LegendContext::LegendContext( ContextHandler2Helper& rParent, LegendModel& rModel ) :
    ContextBase< LegendModel >( rParent, rModel )
{
}

LegendContext::~LegendContext()
{
}

ContextHandlerRef LegendContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
{
    // this context handler is used for <c:legend> only
    switch( nElement )
    {
        case C_TOKEN( layout ):
            return new LayoutContext( *this, mrModel.mxLayout.create() );

        case C_TOKEN( legendPos ):
            mrModel.mnPosition = rAttribs.getToken( XML_val, XML_r );
            return 0;

        case C_TOKEN( overlay ):
            // default is 'false', not 'true' as specified
            mrModel.mbOverlay = rAttribs.getBool( XML_val, false );
            return 0;

        case C_TOKEN( spPr ):
            return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() );

        case C_TOKEN( txPr ):
            return new TextBodyContext( *this, mrModel.mxTextProp.create() );
    }
    return 0;
}

} // namespace chart
} // namespace drawingml
} // namespace oox

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>fix title overly MSO2007 vs OOXML import<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 "drawingml/chart/titlecontext.hxx"

#include "drawingml/shapepropertiescontext.hxx"
#include "drawingml/textbodycontext.hxx"
#include "drawingml/chart/datasourcecontext.hxx"
#include "drawingml/chart/titlemodel.hxx"

#include "rtl/ustrbuf.hxx"
#include <osl/diagnose.h>

namespace oox {
namespace drawingml {
namespace chart {

using ::oox::core::ContextHandler2Helper;
using ::oox::core::ContextHandlerRef;

TextContext::TextContext( ContextHandler2Helper& rParent, TextModel& rModel ) :
    ContextBase< TextModel >( rParent, rModel )
{
}

TextContext::~TextContext()
{
}

ContextHandlerRef TextContext::onCreateContext( sal_Int32 nElement, const AttributeList& )
{
    // this context handler is used for <c:tx> and embedded <c:v> elements
    if( isCurrentElement( C_TOKEN( tx ) ) ) switch( nElement )
    {
        case C_TOKEN( rich ):
            return new TextBodyContext( *this, mrModel.mxTextBody.create() );

        case C_TOKEN( strRef ):
            OSL_ENSURE( !mrModel.mxDataSeq, "TextContext::onCreateContext - multiple data sequences" );
            return new StringSequenceContext( *this, mrModel.mxDataSeq.create() );

        case C_TOKEN( v ):
            OSL_ENSURE( !mrModel.mxDataSeq, "TextContext::onCreateContext - multiple data sequences" );
            return this;    // collect value in onCharacters()
    }
    return 0;
}

void TextContext::onCharacters( const OUString& rChars )
{
    if( isCurrentElement( C_TOKEN( v ) ) )
    {
        // Static text is stored as a single string formula token for Excel document.
        OUStringBuffer aBuf;
        aBuf.append('"').append(rChars).append('"');
        mrModel.mxDataSeq.create().maFormula = aBuf.makeStringAndClear();

        // Also store it as a single element type for non-Excel document.
        mrModel.mxDataSeq->maData[0] <<= rChars;
    }
}

TitleContext::TitleContext( ContextHandler2Helper& rParent, TitleModel& rModel ) :
    ContextBase< TitleModel >( rParent, rModel )
{
}

TitleContext::~TitleContext()
{
}

ContextHandlerRef TitleContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
{
    bool bMSO2007Doc = getFilter().isMSO2007Document();
    // this context handler is used for <c:title> only
    switch( nElement )
    {
        case C_TOKEN( layout ):
            return new LayoutContext( *this, mrModel.mxLayout.create() );

        case C_TOKEN( overlay ):
            mrModel.mbOverlay = rAttribs.getBool( XML_val, !bMSO2007Doc );
            return 0;

        case C_TOKEN( spPr ):
            return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() );

        case C_TOKEN( tx ):
            return new TextContext( *this, mrModel.mxText.create() );

        case C_TOKEN( txPr ):
            return new TextBodyContext( *this, mrModel.mxTextProp.create() );
    }
    return 0;
}

LegendContext::LegendContext( ContextHandler2Helper& rParent, LegendModel& rModel ) :
    ContextBase< LegendModel >( rParent, rModel )
{
}

LegendContext::~LegendContext()
{
}

ContextHandlerRef LegendContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
{
    // this context handler is used for <c:legend> only
    switch( nElement )
    {
        case C_TOKEN( layout ):
            return new LayoutContext( *this, mrModel.mxLayout.create() );

        case C_TOKEN( legendPos ):
            mrModel.mnPosition = rAttribs.getToken( XML_val, XML_r );
            return 0;

        case C_TOKEN( overlay ):
            // default is 'false', not 'true' as specified
            mrModel.mbOverlay = rAttribs.getBool( XML_val, false );
            return 0;

        case C_TOKEN( spPr ):
            return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() );

        case C_TOKEN( txPr ):
            return new TextBodyContext( *this, mrModel.mxTextProp.create() );
    }
    return 0;
}

} // namespace chart
} // namespace drawingml
} // namespace oox

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


<commit_before>//===-- CLIDebugger.cpp - Command Line Interface to the Debugger ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the main implementation of the Command Line Interface to
// the debugger.
//
//===----------------------------------------------------------------------===//

#include "CLIDebugger.h"
#include "CLICommand.h"
#include "llvm/Debugger/SourceFile.h"
#include "Support/StringExtras.h"
#include <iostream>
using namespace llvm;

/// CLIDebugger constructor - This initializes the debugger to its default
/// state, and initializes the command table.
///
CLIDebugger::CLIDebugger()
  : TheProgramInfo(0), TheRuntimeInfo(0), Prompt("(llvm-db) "), ListSize(10) {
  // Initialize instance variables
  CurrentFile = 0;
  LineListedStart = 1;
  LineListedEnd = 1;
  LastCurrentFrame = 0;
  CurrentLanguage = 0;

  CLICommand *C;
  //===--------------------------------------------------------------------===//
  // Program startup and shutdown options
  //
  addCommand("file", new BuiltinCLICommand(
    "Use specified file as the program to be debugged",
    "The debugger looks in the current directory and the program $PATH for the"
    " specified LLVM program.  It then unloads the currently loaded program and"
    " loads the specified program.\n",
    &CLIDebugger::fileCommand));

  addCommand("create", new BuiltinCLICommand(
    "Start the current program, stopping execution in main",
    "This command creates an instance of the current program, but stops"
    " execution immediately.",
    &CLIDebugger::createCommand));

  addCommand("kill", new BuiltinCLICommand(
    "Kills the execution of the current program being debugged", "",
    &CLIDebugger::killCommand));

  addCommand("quit", new BuiltinCLICommand(
    "Exit the debugger", "",
    &CLIDebugger::quitCommand));

  //===--------------------------------------------------------------------===//
  // Program execution commands
  //
  addCommand("run", C = new BuiltinCLICommand(
    "Start the program running from the beginning", "",
    &CLIDebugger::runCommand));
  addCommand("r", C);

  addCommand("cont", C = new BuiltinCLICommand(
    "Continue program being debugged until the next stop point", "",
    &CLIDebugger::contCommand));
  addCommand("c", C); addCommand("fg", C);

  addCommand("step", C = new BuiltinCLICommand(
    "Step program until it reaches a new source line", "",
    &CLIDebugger::stepCommand));
  addCommand("s", C);

  addCommand("next", C = new BuiltinCLICommand(
    "Step program until it reaches a new source line, stepping over calls", "",
    &CLIDebugger::nextCommand));
  addCommand("n", C);

  addCommand("finish", new BuiltinCLICommand(
    "Execute until the selected stack frame returns",
   "Upon return, the value returned is printed and put in the value history.\n",
    &CLIDebugger::finishCommand));

  //===--------------------------------------------------------------------===//
  // Stack frame commands
  //
  addCommand("backtrace", C = new BuiltinCLICommand(
   "Print backtrace of all stack frames, or innermost COUNT frames",
   "FIXME: describe.  Takes 'n', '-n' or 'full'\n",
    &CLIDebugger::backtraceCommand));
  addCommand("bt", C);

  addCommand("up", new BuiltinCLICommand(
    "Select and print stack frame that called this one",
    "An argument says how many frames up to go.\n",
    &CLIDebugger::upCommand));

  addCommand("down", new BuiltinCLICommand(
    "Select and print stack frame called by this one",
    "An argument says how many frames down go.\n",
    &CLIDebugger::downCommand));

  addCommand("frame", C = new BuiltinCLICommand(
    "Select and print a stack frame",
 "With no argument, print the selected stack frame.  (See also 'info frame').\n"
 "An argument specifies the frame to select.\n",
    &CLIDebugger::frameCommand));
  addCommand("f", C);

  //===--------------------------------------------------------------------===//
  // Breakpoint related commands
  //
  addCommand("break", C = new BuiltinCLICommand(
   "Set breakpoint at specified line or function",
   "FIXME: describe.\n",
    &CLIDebugger::breakCommand));
  addCommand("b", C);

  //===--------------------------------------------------------------------===//
  // Miscellaneous commands
  //
  addCommand("info", new BuiltinCLICommand(
    "Generic command for showing things about the program being debugged",
    "FIXME: document\n",
    &CLIDebugger::infoCommand));

  addCommand("list", C = new BuiltinCLICommand(
    "List specified function or line",
    "FIXME: document\n",
    &CLIDebugger::listCommand));
  addCommand("l", C);

  addCommand("set", new BuiltinCLICommand(
    "Change program or debugger variable",
    "FIXME: document\n",
    &CLIDebugger::setCommand));

  addCommand("show", new BuiltinCLICommand(
    "Generic command for showing things about the debugger",
    "FIXME: document\n",
    &CLIDebugger::showCommand));

  addCommand("help", C = new BuiltinCLICommand(
    "Prints information about available commands", "",
    &CLIDebugger::helpCommand));
  addCommand("h", C);
}

/// addCommand - Add a command to the CommandTable, potentially displacing a
/// preexisting command.
void CLIDebugger::addCommand(const std::string &Option, CLICommand *Cmd) {
  assert(Cmd && "Cannot set a null command!");
  CLICommand *&CS = CommandTable[Option];
  if (CS == Cmd) return; // noop

  // If we already have a command, decrement the command's reference count.
  if (CS) {
    CS->removeOptionName(Option);
    CS->dropRef();
  }
  CS = Cmd;

  // Remember that we are using this command.
  Cmd->addRef();
  Cmd->addOptionName(Option);
}

static bool isValidPrefix(const std::string &Prefix, const std::string &Option){
  return Prefix.size() <= Option.size() &&
         Prefix == std::string(Option.begin(), Option.begin()+Prefix.size());
}

/// getCommand - This looks up the specified command using a fuzzy match.
/// If the string exactly matches a command or is an unambiguous prefix of a
/// command, it returns the command.  Otherwise it throws an exception
/// indicating the possible ambiguous choices.
CLICommand *CLIDebugger::getCommand(const std::string &Command) {

  // Look up the command in the table.
  std::map<std::string, CLICommand*>::iterator CI =
    CommandTable.lower_bound(Command);

  if (Command == "") {
    throw "Null command not implemented yet.";
  } else if (CI == CommandTable.end() ||
             !isValidPrefix(Command, CI->first)) {
    // If this command has no relation to anything in the command table,
    // print the error message.
    throw "Unknown command: '" + Command +
          "'.  Use 'help' for list of commands.";
  } else if (CI->first == Command) {
    // We have an exact match on the command
    return CI->second;
  } else {
    // Otherwise, we have a prefix match.  Check to see if this is
    // unambiguous, and if so, run it.
    std::map<std::string, CLICommand*>::iterator CI2 = CI;

    // If the next command is a valid completion of this one, we are
    // ambiguous.
    if (++CI2 != CommandTable.end() && isValidPrefix(Command, CI2->first)) {
      std::string ErrorMsg =
        "Ambiguous command '" + Command + "'.  Options: " + CI->first;
      for (++CI; CI != CommandTable.end() &&
             isValidPrefix(Command, CI->first); ++CI)
        ErrorMsg += ", " + CI->first;
      throw ErrorMsg;
    } else {
      // It's an unambiguous prefix of a command, use it.
      return CI->second;
    }
  }
}

/// run - Start the debugger, returning when the user exits the debugger.  This
/// starts the main event loop of the CLI debugger.
///
int CLIDebugger::run() {
  std::string Command;
  std::cout << Prompt;

  // Continue reading commands until the end of file.
  while (getline(std::cin, Command)) {
    std::string Arguments = Command;

    // Split off the command from the arguments to the command.
    Command = getToken(Arguments, " \t\n\v\f\r\\/;.*&");

    try {
      // Look up the command and execute it.
      getCommand(Command)->runCommand(*this, Arguments);

    } catch (int RetVal) {
      // The quit command exits the command loop by throwing an integer return
      // code.
      return RetVal;
    } catch (const std::string &Error) {
      std::cout << "Error: " << Error << "\n";
    } catch (const char *Error) {
      std::cout << "Error: " << Error << "\n";
    } catch (const NonErrorException &E) {
      std::cout << E.getMessage() << "\n";
    } catch (...) {
      std::cout << "ERROR: Debugger caught unexpected exception!\n";
      // Attempt to continue.
    }

    // Write the prompt to get the next bit of user input
    std::cout << Prompt;
  }

  return 0;
}

/// askYesNo - Ask the user a question, and demand a yes/no response.  If
/// the user says yes, return true.
///
bool CLIDebugger::askYesNo(const std::string &Message) const {
  std::string Answer;
  std::cout << Message << " (y or n) " << std::flush;
  while (getline(std::cin, Answer)) {
    std::string Val = getToken(Answer);
    if (getToken(Answer).empty()) {
      if (Val == "yes" || Val == "y" || Val == "YES" || Val == "Y" ||
          Val == "Yes")
        return true;
      if (Val == "no" || Val == "n" || Val == "NO" || Val == "N" ||
          Val == "No")
        return false;
    }

    std::cout << "Please answer y or n.\n" << Message << " (y or n) "
              << std::flush;
  }

  // Ran out of input?
  return false;
}
<commit_msg>implement the "null command" which repeats the last command<commit_after>//===-- CLIDebugger.cpp - Command Line Interface to the Debugger ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the main implementation of the Command Line Interface to
// the debugger.
//
//===----------------------------------------------------------------------===//

#include "CLIDebugger.h"
#include "CLICommand.h"
#include "llvm/Debugger/SourceFile.h"
#include "Support/StringExtras.h"
#include <iostream>
using namespace llvm;

/// CLIDebugger constructor - This initializes the debugger to its default
/// state, and initializes the command table.
///
CLIDebugger::CLIDebugger()
  : TheProgramInfo(0), TheRuntimeInfo(0), Prompt("(llvm-db) "), ListSize(10) {
  // Initialize instance variables
  CurrentFile = 0;
  LineListedStart = 1;
  LineListedEnd = 1;
  LastCurrentFrame = 0;
  CurrentLanguage = 0;

  CLICommand *C;
  //===--------------------------------------------------------------------===//
  // Program startup and shutdown options
  //
  addCommand("file", new BuiltinCLICommand(
    "Use specified file as the program to be debugged",
    "The debugger looks in the current directory and the program $PATH for the"
    " specified LLVM program.  It then unloads the currently loaded program and"
    " loads the specified program.\n",
    &CLIDebugger::fileCommand));

  addCommand("create", new BuiltinCLICommand(
    "Start the program, halting its execution in main",
    "This command creates an instance of the current program, but stops"
    "\nexecution immediately.\n",
    &CLIDebugger::createCommand));

  addCommand("kill", new BuiltinCLICommand(
    "Kills the execution of the current program being debugged", "",
    &CLIDebugger::killCommand));

  addCommand("quit", new BuiltinCLICommand(
    "Exit the debugger", "",
    &CLIDebugger::quitCommand));

  //===--------------------------------------------------------------------===//
  // Program execution commands
  //
  addCommand("run", C = new BuiltinCLICommand(
    "Start the program running from the beginning", "",
    &CLIDebugger::runCommand));
  addCommand("r", C);

  addCommand("cont", C = new BuiltinCLICommand(
    "Continue program being debugged until the next stop point", "",
    &CLIDebugger::contCommand));
  addCommand("c", C); addCommand("fg", C);

  addCommand("step", C = new BuiltinCLICommand(
    "Step program until it reaches a new source line", "",
    &CLIDebugger::stepCommand));
  addCommand("s", C);

  addCommand("next", C = new BuiltinCLICommand(
    "Step program until it reaches a new source line, stepping over calls", "",
    &CLIDebugger::nextCommand));
  addCommand("n", C);

  addCommand("finish", new BuiltinCLICommand(
    "Execute until the selected stack frame returns",
   "Upon return, the value returned is printed and put in the value history.\n",
    &CLIDebugger::finishCommand));

  //===--------------------------------------------------------------------===//
  // Stack frame commands
  //
  addCommand("backtrace", C = new BuiltinCLICommand(
   "Print backtrace of all stack frames, or innermost COUNT frames",
   "FIXME: describe.  Takes 'n', '-n' or 'full'\n",
    &CLIDebugger::backtraceCommand));
  addCommand("bt", C);

  addCommand("up", new BuiltinCLICommand(
    "Select and print stack frame that called this one",
    "An argument says how many frames up to go.\n",
    &CLIDebugger::upCommand));

  addCommand("down", new BuiltinCLICommand(
    "Select and print stack frame called by this one",
    "An argument says how many frames down go.\n",
    &CLIDebugger::downCommand));

  addCommand("frame", C = new BuiltinCLICommand(
    "Select and print a stack frame",
 "With no argument, print the selected stack frame.  (See also 'info frame').\n"
 "An argument specifies the frame to select.\n",
    &CLIDebugger::frameCommand));
  addCommand("f", C);

  //===--------------------------------------------------------------------===//
  // Breakpoint related commands
  //
  addCommand("break", C = new BuiltinCLICommand(
   "Set breakpoint at specified line or function",
   "FIXME: describe.\n",
    &CLIDebugger::breakCommand));
  addCommand("b", C);

  //===--------------------------------------------------------------------===//
  // Miscellaneous commands
  //
  addCommand("info", new BuiltinCLICommand(
    "Generic command for showing things about the program being debugged",
    "FIXME: document\n",
    &CLIDebugger::infoCommand));

  addCommand("list", C = new BuiltinCLICommand(
    "List specified function or line",
    "FIXME: document\n",
    &CLIDebugger::listCommand));
  addCommand("l", C);

  addCommand("set", new BuiltinCLICommand(
    "Change program or debugger variable",
    "FIXME: document\n",
    &CLIDebugger::setCommand));

  addCommand("show", new BuiltinCLICommand(
    "Generic command for showing things about the debugger",
    "FIXME: document\n",
    &CLIDebugger::showCommand));

  addCommand("help", C = new BuiltinCLICommand(
    "Prints information about available commands", "",
    &CLIDebugger::helpCommand));
  addCommand("h", C);
}

/// addCommand - Add a command to the CommandTable, potentially displacing a
/// preexisting command.
void CLIDebugger::addCommand(const std::string &Option, CLICommand *Cmd) {
  assert(Cmd && "Cannot set a null command!");
  CLICommand *&CS = CommandTable[Option];
  if (CS == Cmd) return; // noop

  // If we already have a command, decrement the command's reference count.
  if (CS) {
    CS->removeOptionName(Option);
    CS->dropRef();
  }
  CS = Cmd;

  // Remember that we are using this command.
  Cmd->addRef();
  Cmd->addOptionName(Option);
}

static bool isValidPrefix(const std::string &Prefix, const std::string &Option){
  return Prefix.size() <= Option.size() &&
         Prefix == std::string(Option.begin(), Option.begin()+Prefix.size());
}

/// getCommand - This looks up the specified command using a fuzzy match.
/// If the string exactly matches a command or is an unambiguous prefix of a
/// command, it returns the command.  Otherwise it throws an exception
/// indicating the possible ambiguous choices.
CLICommand *CLIDebugger::getCommand(const std::string &Command) {

  // Look up the command in the table.
  std::map<std::string, CLICommand*>::iterator CI =
    CommandTable.lower_bound(Command);

  if (Command == "") {
    throw "Null command should not get here!";
  } else if (CI == CommandTable.end() ||
             !isValidPrefix(Command, CI->first)) {
    // If this command has no relation to anything in the command table,
    // print the error message.
    throw "Unknown command: '" + Command +
          "'.  Use 'help' for list of commands.";
  } else if (CI->first == Command) {
    // We have an exact match on the command
    return CI->second;
  } else {
    // Otherwise, we have a prefix match.  Check to see if this is
    // unambiguous, and if so, run it.
    std::map<std::string, CLICommand*>::iterator CI2 = CI;

    // If the next command is a valid completion of this one, we are
    // ambiguous.
    if (++CI2 != CommandTable.end() && isValidPrefix(Command, CI2->first)) {
      std::string ErrorMsg =
        "Ambiguous command '" + Command + "'.  Options: " + CI->first;
      for (++CI; CI != CommandTable.end() &&
             isValidPrefix(Command, CI->first); ++CI)
        ErrorMsg += ", " + CI->first;
      throw ErrorMsg;
    } else {
      // It's an unambiguous prefix of a command, use it.
      return CI->second;
    }
  }
}

/// run - Start the debugger, returning when the user exits the debugger.  This
/// starts the main event loop of the CLI debugger.
///
int CLIDebugger::run() {
  std::string Command;
  std::cout << Prompt;

  // Keep track of the last command issued, so that we can reissue it if the
  // user hits enter as the command.
  CLICommand *LastCommand = 0;
  std::string LastArgs;

  // Continue reading commands until the end of file.
  while (getline(std::cin, Command)) {
    std::string Arguments = Command;

    // Split off the command from the arguments to the command.
    Command = getToken(Arguments, " \t\n\v\f\r\\/;.*&");

    try {
      CLICommand *CurCommand;

      if (Command == "") {
        CurCommand = LastCommand;
        Arguments = LastArgs;
      } else {
        CurCommand = getCommand(Command);
      }

      // Save the command we are running in case the user wants us to repeat it
      // next time.
      LastCommand = CurCommand;
      LastArgs = Arguments;

      // Finally, execute the command.
      if (CurCommand)
        CurCommand->runCommand(*this, Arguments);

    } catch (int RetVal) {
      // The quit command exits the command loop by throwing an integer return
      // code.
      return RetVal;
    } catch (const std::string &Error) {
      std::cout << "Error: " << Error << "\n";
    } catch (const char *Error) {
      std::cout << "Error: " << Error << "\n";
    } catch (const NonErrorException &E) {
      std::cout << E.getMessage() << "\n";
    } catch (...) {
      std::cout << "ERROR: Debugger caught unexpected exception!\n";
      // Attempt to continue.
    }

    // Write the prompt to get the next bit of user input
    std::cout << Prompt;
  }

  return 0;
}

/// askYesNo - Ask the user a question, and demand a yes/no response.  If
/// the user says yes, return true.
///
bool CLIDebugger::askYesNo(const std::string &Message) const {
  std::string Answer;
  std::cout << Message << " (y or n) " << std::flush;
  while (getline(std::cin, Answer)) {
    std::string Val = getToken(Answer);
    if (getToken(Answer).empty()) {
      if (Val == "yes" || Val == "y" || Val == "YES" || Val == "Y" ||
          Val == "Yes")
        return true;
      if (Val == "no" || Val == "n" || Val == "NO" || Val == "N" ||
          Val == "No")
        return false;
    }

    std::cout << "Please answer y or n.\n" << Message << " (y or n) "
              << std::flush;
  }

  // Ran out of input?
  return false;
}
<|endoftext|>