<commit_before>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the LiveSupport project.
    http://livesupport.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

    LiveSupport is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    LiveSupport 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with LiveSupport; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author: fgerlits $
    Version  : $Revision: 1.17 $
    Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/products/gLiveSupport/src/MasterPanelWindow.cxx,v $

------------------------------------------------------------------------------*/

/* ============================================================ include files */

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

#include <iostream>
#include <unicode/msgfmt.h>
#include <gtkmm/label.h>
#include <gtkmm/main.h>

#include "LiveSupport/Core/TimeConversion.h"
#include "UploadFileWindow.h"
#include "ScratchpadWindow.h"
#include "MasterPanelWindow.h"

using namespace LiveSupport;
using namespace LiveSupport::GLiveSupport;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/* ===============================================  local function prototypes */

/* =============================================================  module code */

/*------------------------------------------------------------------------------
 *  Constructor.
 *----------------------------------------------------------------------------*/
MasterPanelWindow :: MasterPanelWindow (Ptr<GLiveSupport>::Ref    gLiveSupport,
                                        Ptr<ResourceBundle>::Ref  bundle)
                                                                    throw ()
                        : LocalizedObject(bundle)
{
    this->gLiveSupport = gLiveSupport;

    Ptr<WidgetFactory>::Ref widgetFactory = WidgetFactory::getInstance();

    // TODO: remove hard-coded station logo path reference
    radioLogoWidget = Gtk::manage(new Gtk::Image("var/stationLogo.png"));
    radioLogoWidget->set_size_request(158, 104);

    // set up the layout, which is a button box
    layout = Gtk::manage(new Gtk::Table());

    // set up the time label
    timeWidget = Gtk::manage(new Gtk::Label("time"));
    timeBin = Gtk::manage(widgetFactory->createBlueBin());
    timeBin->add(*timeWidget);
    timeBin->set_size_request(153, 104);

    // set up the now playing widget
    nowPlayingWidget = Gtk::manage(new Gtk::Label("now playing"));
    nowPlayingBin = Gtk::manage(widgetFactory->createDarkBlueBin());
    nowPlayingBin->add(*nowPlayingWidget);
    timeBin->set_size_request(-1, 104);

    // set up the VU meter widget
    vuMeterWidget = Gtk::manage(new Gtk::Label("VU meter"));
    vuMeterBin = Gtk::manage(widgetFactory->createBlueBin());
    vuMeterBin->add(*vuMeterWidget);
    vuMeterBin->set_size_request(400, 40);
    // set up the next playing widget
    nextPlayingWidget = Gtk::manage(new Gtk::Label("next playing"));
    nextPlayingBin = Gtk::manage(widgetFactory->createBlueBin());
    nextPlayingBin->add(*nextPlayingWidget);
    nextPlayingBin->set_size_request(400, 59);

    // create the bottom bar
    bottomBar = Gtk::manage(new Gtk::Table());
    bottomBar->set_size_request(-1, 30);
    buttonBar = Gtk::manage(new Gtk::Table());
    buttonBarAlignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_LEFT,
                                                        Gtk::ALIGN_CENTER,
                                                        0, 0));
    buttonBarAlignment->add(*buttonBar);
    userInfoWidget = Gtk::manage(new MasterPanelUserInfoWidget(gLiveSupport,
                                                               bundle));
    userInfoAlignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
                                                       Gtk::ALIGN_CENTER,
                                                       0, 0));
    userInfoAlignment->add(*userInfoWidget);
    bottomBar->attach(*buttonBarAlignment, 0, 1, 0, 1,
                      Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    bottomBar->attach(*userInfoAlignment,  1, 2, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    // set up the main window, and show everything
    // all the localized widgets were set up in changeLanguage()
    set_border_width(10);
    layout->attach(*timeBin,         0, 1, 0, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*nowPlayingBin,   1, 2, 0, 2,
                   Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                   5, 0);
    layout->attach(*vuMeterBin,      2, 3, 0, 1,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*nextPlayingBin,  2, 3, 1, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*radioLogoWidget, 3, 4, 0, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    5, 0);
    layout->attach(*bottomBar,       0, 4, 2, 3,
                    Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    add(*layout);

    // set the background to white
    bgColor = Colors::getColor(Colors::White);
    modify_bg(Gtk::STATE_NORMAL, bgColor);

    // set the size and location of the window, according to the screen size
    Glib::RefPtr<Gdk::Screen>   screen = get_screen();
    int                         width;
    int                         height;
    get_size(width, height);
    width = screen->get_width();
    set_default_size(width, height);
    move(0, 0);
    set_decorated(false);

    // set the localized resources
    changeLanguage(bundle);

    // show what's there to see
    showAnonymousUI();

    // set the timer, that will update timeWidget
    setTimer();
}

/*------------------------------------------------------------------------------
 *  Destructor.
 *----------------------------------------------------------------------------*/
MasterPanelWindow :: ~MasterPanelWindow (void)                        throw ()
{
    resetTimer();
    gLiveSupport->stopAudio();
}

/*------------------------------------------------------------------------------
 *  Change the language of the panel
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: changeLanguage(Ptr<ResourceBundle>::Ref    bundle)
                                                                    throw ()
{
    setBundle(bundle);

    try {
        set_title(*getResourceUstring("windowTitle"));

        Ptr<WidgetFactory>::Ref wf = WidgetFactory::getInstance();

        uploadFileButton = wf->createButton(
                                *getResourceUstring("uploadFileButtonLabel"));
        scratchpadButton = wf->createButton(
                                *getResourceUstring("scratchpadButtonLabel"));
        simplePlaylistMgmtButton = wf->createButton(
                        *getResourceUstring("simplePlaylistMgmtButtonLabel"));
        schedulerButton = wf->createButton(
                                *getResourceUstring("schedulerButtonLabel"));
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
    }

    userInfoWidget->changeLanguage(bundle);

    // re-attach the localized widgets to the layout
    buttonBar->attach(*uploadFileButton,           0, 1, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*scratchpadButton,           1, 2, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*simplePlaylistMgmtButton,   2, 3, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*schedulerButton,            3, 4, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);

    // re-bind events to the buttons
    uploadFileButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onUploadFileButtonClicked));
    scratchpadButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onScratchpadButtonClicked));
    simplePlaylistMgmtButton->signal_clicked().connect(
            sigc::mem_fun(*this,
                 &MasterPanelWindow::onSimplePlaylistMgmtButtonClicked));
    schedulerButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onSchedulerButtonClicked));

}

/*------------------------------------------------------------------------------
 *  Set the timer
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: setTimer(void)                                  throw ()
{
    sigc::slot<bool>    slot = sigc::bind(sigc::mem_fun(*this,
                                              &MasterPanelWindow::onUpdateTime),
                                              0);

    // set the timer to active once a second
    timer.reset(new sigc::connection(
                                  Glib::signal_timeout().connect(slot, 1000)));
}

/*------------------------------------------------------------------------------
 *  Clear the timer
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: resetTimer(void)                                throw ()
{
    timer->disconnect();
    timer.reset();
}

/*------------------------------------------------------------------------------
 *  Update the timeWidget display, with the current time
 *----------------------------------------------------------------------------*/
bool
MasterPanelWindow :: onUpdateTime(int   dummy)                       throw ()
{
    Ptr<const ptime>::Ref   now = gLiveSupport->getScheduler()
                                              ->getSchedulerTime();

    if (now.get()) {
        time_duration           dayTime = now->time_of_day();
        // get the time of day, only up to a second precision
        time_duration           dayTimeSec(dayTime.hours(),
                                           dayTime.minutes(),
                                           dayTime.seconds(),
                                           0);

        timeWidget->set_text(to_simple_string(dayTimeSec));
    }

    return true;
}

/*------------------------------------------------------------------------------
 *  The event when the upload file button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onUploadFileButtonClicked(void)                 throw ()
{
    Ptr<ResourceBundle>::Ref    bundle;
    try {
        bundle       = getBundle("uploadFileWindow");
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        return;
    }

    Ptr<UploadFileWindow>::Ref  uploadWindow(new UploadFileWindow(gLiveSupport,
                                                                  bundle));

    Gtk::Main::run(*uploadWindow);
}

/*------------------------------------------------------------------------------
 *  The event when the Scratchpad button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onScratchpadButtonClicked(void)                throw ()
{
    if (!scratchpadWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("scratchpadWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        scratchpadWindow.reset(new ScratchpadWindow(gLiveSupport, bundle));
    }

    if (!scratchpadWindow->is_visible()) {
        scratchpadWindow->show();
    }

    scratchpadWindow->showContents();
}

/*------------------------------------------------------------------------------
 *  The event when the Simple Playlist Management button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onSimplePlaylistMgmtButtonClicked(void)        throw ()
{
    if (!simplePlaylistMgmtWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("simplePlaylistManagementWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        simplePlaylistMgmtWindow.reset(
                new SimplePlaylistManagementWindow(gLiveSupport, bundle));
    }

    if (!simplePlaylistMgmtWindow->is_visible()) {
        simplePlaylistMgmtWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  The event when the Scheduler button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onSchedulerButtonClicked(void)                 throw ()
{
    if (!schedulerWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("schedulerWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        schedulerWindow.reset(new SchedulerWindow(gLiveSupport, bundle));
    }

    if (!schedulerWindow->is_visible()) {
        schedulerWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  Show only the UI components that are visible when no one is logged in
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: showAnonymousUI(void)                          throw ()
{
    show_all();
    buttonBar->hide();
    uploadFileButton->hide();
    scratchpadButton->hide();
    simplePlaylistMgmtButton->hide();
    schedulerButton->hide();
}

/*------------------------------------------------------------------------------
 *  Show the UI components that are visible to a specific user.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: showLoggedInUI(void)                           throw ()
{
    show_all();
}

<commit_msg>added workaround for when the client can't access the scheduler (and tries to display the time). fix for issue #810 see http://bugs.campware.org/view.php?id=810<commit_after>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the LiveSupport project.
    http://livesupport.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

    LiveSupport is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    LiveSupport 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with LiveSupport; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author: maroy $
    Version  : $Revision: 1.18 $
    Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/products/gLiveSupport/src/MasterPanelWindow.cxx,v $

------------------------------------------------------------------------------*/

/* ============================================================ include files */

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

#include <iostream>
#include <unicode/msgfmt.h>
#include <gtkmm/label.h>
#include <gtkmm/main.h>

#include "LiveSupport/Core/TimeConversion.h"
#include "UploadFileWindow.h"
#include "ScratchpadWindow.h"
#include "MasterPanelWindow.h"

using namespace LiveSupport;
using namespace LiveSupport::GLiveSupport;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/* ===============================================  local function prototypes */

/* =============================================================  module code */

/*------------------------------------------------------------------------------
 *  Constructor.
 *----------------------------------------------------------------------------*/
MasterPanelWindow :: MasterPanelWindow (Ptr<GLiveSupport>::Ref    gLiveSupport,
                                        Ptr<ResourceBundle>::Ref  bundle)
                                                                    throw ()
                        : LocalizedObject(bundle)
{
    this->gLiveSupport = gLiveSupport;

    Ptr<WidgetFactory>::Ref widgetFactory = WidgetFactory::getInstance();

    // TODO: remove hard-coded station logo path reference
    radioLogoWidget = Gtk::manage(new Gtk::Image("var/stationLogo.png"));
    radioLogoWidget->set_size_request(158, 104);

    // set up the layout, which is a button box
    layout = Gtk::manage(new Gtk::Table());

    // set up the time label
    timeWidget = Gtk::manage(new Gtk::Label("time"));
    timeBin = Gtk::manage(widgetFactory->createBlueBin());
    timeBin->add(*timeWidget);
    timeBin->set_size_request(153, 104);

    // set up the now playing widget
    nowPlayingWidget = Gtk::manage(new Gtk::Label("now playing"));
    nowPlayingBin = Gtk::manage(widgetFactory->createDarkBlueBin());
    nowPlayingBin->add(*nowPlayingWidget);
    timeBin->set_size_request(-1, 104);

    // set up the VU meter widget
    vuMeterWidget = Gtk::manage(new Gtk::Label("VU meter"));
    vuMeterBin = Gtk::manage(widgetFactory->createBlueBin());
    vuMeterBin->add(*vuMeterWidget);
    vuMeterBin->set_size_request(400, 40);
    // set up the next playing widget
    nextPlayingWidget = Gtk::manage(new Gtk::Label("next playing"));
    nextPlayingBin = Gtk::manage(widgetFactory->createBlueBin());
    nextPlayingBin->add(*nextPlayingWidget);
    nextPlayingBin->set_size_request(400, 59);

    // create the bottom bar
    bottomBar = Gtk::manage(new Gtk::Table());
    bottomBar->set_size_request(-1, 30);
    buttonBar = Gtk::manage(new Gtk::Table());
    buttonBarAlignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_LEFT,
                                                        Gtk::ALIGN_CENTER,
                                                        0, 0));
    buttonBarAlignment->add(*buttonBar);
    userInfoWidget = Gtk::manage(new MasterPanelUserInfoWidget(gLiveSupport,
                                                               bundle));
    userInfoAlignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
                                                       Gtk::ALIGN_CENTER,
                                                       0, 0));
    userInfoAlignment->add(*userInfoWidget);
    bottomBar->attach(*buttonBarAlignment, 0, 1, 0, 1,
                      Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    bottomBar->attach(*userInfoAlignment,  1, 2, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    // set up the main window, and show everything
    // all the localized widgets were set up in changeLanguage()
    set_border_width(10);
    layout->attach(*timeBin,         0, 1, 0, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*nowPlayingBin,   1, 2, 0, 2,
                   Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                   5, 0);
    layout->attach(*vuMeterBin,      2, 3, 0, 1,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*nextPlayingBin,  2, 3, 1, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*radioLogoWidget, 3, 4, 0, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    5, 0);
    layout->attach(*bottomBar,       0, 4, 2, 3,
                    Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    add(*layout);

    // set the background to white
    bgColor = Colors::getColor(Colors::White);
    modify_bg(Gtk::STATE_NORMAL, bgColor);

    // set the size and location of the window, according to the screen size
    Glib::RefPtr<Gdk::Screen>   screen = get_screen();
    int                         width;
    int                         height;
    get_size(width, height);
    width = screen->get_width();
    set_default_size(width, height);
    move(0, 0);
    set_decorated(false);

    // set the localized resources
    changeLanguage(bundle);

    // show what's there to see
    showAnonymousUI();

    // set the timer, that will update timeWidget
    setTimer();
}

/*------------------------------------------------------------------------------
 *  Destructor.
 *----------------------------------------------------------------------------*/
MasterPanelWindow :: ~MasterPanelWindow (void)                        throw ()
{
    resetTimer();
    gLiveSupport->stopAudio();
}

/*------------------------------------------------------------------------------
 *  Change the language of the panel
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: changeLanguage(Ptr<ResourceBundle>::Ref    bundle)
                                                                    throw ()
{
    setBundle(bundle);

    try {
        set_title(*getResourceUstring("windowTitle"));

        Ptr<WidgetFactory>::Ref wf = WidgetFactory::getInstance();

        uploadFileButton = wf->createButton(
                                *getResourceUstring("uploadFileButtonLabel"));
        scratchpadButton = wf->createButton(
                                *getResourceUstring("scratchpadButtonLabel"));
        simplePlaylistMgmtButton = wf->createButton(
                        *getResourceUstring("simplePlaylistMgmtButtonLabel"));
        schedulerButton = wf->createButton(
                                *getResourceUstring("schedulerButtonLabel"));
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
    }

    userInfoWidget->changeLanguage(bundle);

    // re-attach the localized widgets to the layout
    buttonBar->attach(*uploadFileButton,           0, 1, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*scratchpadButton,           1, 2, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*simplePlaylistMgmtButton,   2, 3, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*schedulerButton,            3, 4, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);

    // re-bind events to the buttons
    uploadFileButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onUploadFileButtonClicked));
    scratchpadButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onScratchpadButtonClicked));
    simplePlaylistMgmtButton->signal_clicked().connect(
            sigc::mem_fun(*this,
                 &MasterPanelWindow::onSimplePlaylistMgmtButtonClicked));
    schedulerButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onSchedulerButtonClicked));

}

/*------------------------------------------------------------------------------
 *  Set the timer
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: setTimer(void)                                  throw ()
{
    sigc::slot<bool>    slot = sigc::bind(sigc::mem_fun(*this,
                                              &MasterPanelWindow::onUpdateTime),
                                              0);

    // set the timer to active once a second
    timer.reset(new sigc::connection(
                                  Glib::signal_timeout().connect(slot, 1000)));
}

/*------------------------------------------------------------------------------
 *  Clear the timer
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: resetTimer(void)                                throw ()
{
    timer->disconnect();
    timer.reset();
}

/*------------------------------------------------------------------------------
 *  Update the timeWidget display, with the current time
 *----------------------------------------------------------------------------*/
bool
MasterPanelWindow :: onUpdateTime(int   dummy)                       throw ()
{
    Ptr<const ptime>::Ref   now;

    try {
        now = gLiveSupport->getScheduler()->getSchedulerTime();
    } catch (XmlRpcException &e) {
        // TODO: handle error
    }

    if (now.get()) {
        time_duration           dayTime = now->time_of_day();
        // get the time of day, only up to a second precision
        time_duration           dayTimeSec(dayTime.hours(),
                                           dayTime.minutes(),
                                           dayTime.seconds(),
                                           0);

        timeWidget->set_text(to_simple_string(dayTimeSec));
    }

    return true;
}

/*------------------------------------------------------------------------------
 *  The event when the upload file button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onUploadFileButtonClicked(void)                 throw ()
{
    Ptr<ResourceBundle>::Ref    bundle;
    try {
        bundle       = getBundle("uploadFileWindow");
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        return;
    }

    Ptr<UploadFileWindow>::Ref  uploadWindow(new UploadFileWindow(gLiveSupport,
                                                                  bundle));

    Gtk::Main::run(*uploadWindow);
}

/*------------------------------------------------------------------------------
 *  The event when the Scratchpad button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onScratchpadButtonClicked(void)                throw ()
{
    if (!scratchpadWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("scratchpadWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        scratchpadWindow.reset(new ScratchpadWindow(gLiveSupport, bundle));
    }

    if (!scratchpadWindow->is_visible()) {
        scratchpadWindow->show();
    }

    scratchpadWindow->showContents();
}

/*------------------------------------------------------------------------------
 *  The event when the Simple Playlist Management button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onSimplePlaylistMgmtButtonClicked(void)        throw ()
{
    if (!simplePlaylistMgmtWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("simplePlaylistManagementWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        simplePlaylistMgmtWindow.reset(
                new SimplePlaylistManagementWindow(gLiveSupport, bundle));
    }

    if (!simplePlaylistMgmtWindow->is_visible()) {
        simplePlaylistMgmtWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  The event when the Scheduler button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onSchedulerButtonClicked(void)                 throw ()
{
    if (!schedulerWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("schedulerWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        schedulerWindow.reset(new SchedulerWindow(gLiveSupport, bundle));
    }

    if (!schedulerWindow->is_visible()) {
        schedulerWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  Show only the UI components that are visible when no one is logged in
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: showAnonymousUI(void)                          throw ()
{
    show_all();
    buttonBar->hide();
    uploadFileButton->hide();
    scratchpadButton->hide();
    simplePlaylistMgmtButton->hide();
    schedulerButton->hide();
}

/*------------------------------------------------------------------------------
 *  Show the UI components that are visible to a specific user.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: showLoggedInUI(void)                           throw ()
{
    show_all();
}

<|endoftext|>


<commit_before>/*
Copyright 2013-present Barefoot Networks, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <fstream>
#include <iostream>

#include "control-plane/p4RuntimeSerializer.h"
#include "ir/ir.h"
#include "ir/json_loader.h"
#include "lib/log.h"
#include "lib/error.h"
#include "lib/exceptions.h"
#include "lib/gc.h"
#include "lib/crash.h"
#include "lib/nullstream.h"
#include "frontends/common/parseInput.h"
#include "frontends/p4/evaluator/evaluator.h"
#include "frontends/p4/frontend.h"
#include "frontends/p4/toP4/toP4.h"
#include "midend.h"

class P4TestOptions : public CompilerOptions {
 public:
    bool parseOnly = false;
    bool validateOnly = false;
    P4TestOptions() {
        registerOption("--parse-only", nullptr,
                       [this](const char*) {
                           parseOnly = true;
                           return true; },
                       "only parse the P4 input, without any further processing");
        registerOption("--validate", nullptr,
                       [this](const char*) {
                           validateOnly = true;
                           return true;
                       },
                       "Validate the P4 input, running just the front-end");
     }
};

using P4TestContext = P4CContextWithOptions<P4TestOptions>;

static void log_dump(const IR::Node *node, const char *head) {
    if (node && LOGGING(1)) {
        if (head)
            std::cout << '+' << std::setw(strlen(head)+6) << std::setfill('-') << "+\n| "
                      << head << " |\n" << '+' << std::setw(strlen(head)+3) << "+" <<
                      std::endl << std::setfill(' ');
        if (LOGGING(2))
            dump(node);
        else
            std::cout << *node << std::endl; }
}

int main(int argc, char *const argv[]) {
    setup_gc_logging();
    setup_signals();

    AutoCompileContext autoP4TestContext(new P4TestContext);
    auto& options = P4TestContext::get().options();
    options.langVersion = CompilerOptions::FrontendVersion::P4_16;
    options.compilerVersion = "0.0.5";

    if (options.process(argc, argv) != nullptr)
        options.setInputFile();
    if (::errorCount() > 0)
        return 1;

    auto program = P4::parseP4File(options);
    auto hook = options.getDebugHook();

    if (program != nullptr && ::errorCount() == 0) {
        if (!options.parseOnly) {
            try {
                P4::FrontEnd fe;
                fe.addDebugHook(hook);
                program = fe.run(options, program);
            } catch (const Util::P4CExceptionBase &bug) {
                std::cerr << bug.what() << std::endl;
                return 1;
            }
        }
        log_dump(program, "Initial program");
        if (program != nullptr && ::errorCount() == 0) {
            if (!options.parseOnly && !options.validateOnly) {
                P4Test::MidEnd midEnd(options);
                midEnd.addDebugHook(hook);
#if 0
                /* doing this breaks the output until we get dump/undump of srcInfo */
                if (options.debugJson) {
                    std::stringstream tmp;
                    JSONGenerator gen(tmp);
                    gen << program;
                    JSONLoader loader(tmp);
                    loader >> program;
                }
#endif
                const IR::ToplevelBlock *top = nullptr;
                try {
                    top = midEnd.process(program);
                } catch (const Util::P4CExceptionBase &bug) {
                    std::cerr << bug.what() << std::endl;
                    return 1;
                }
                log_dump(program, "After midend");
                log_dump(top, "Top level block");
            }
            if (options.dumpJsonFile)
                JSONGenerator(*openFile(options.dumpJsonFile, true), true) << program << std::endl;
            if (options.debugJson) {
                std::stringstream ss1, ss2;
                JSONGenerator gen1(ss1), gen2(ss2);
                gen1 << program;

                const IR::Node* node = nullptr;
                JSONLoader loader(ss1);
                loader >> node;

                gen2 << node;
                if (ss1.str() != ss2.str()) {
                    error("json mismatch");
                    std::ofstream t1("t1.json"), t2("t2.json");
                    t1 << ss1.str() << std::flush;
                    t2 << ss2.str() << std::flush;
                    system("json_diff t1.json t2.json");
                }
            }
        }
    }

    P4::serializeP4RuntimeIfRequired(program, options);

    if (Log::verbose())
        std::cerr << "Done." << std::endl;
    return ::errorCount() > 0;
}
<commit_msg>Fix GCC unused return value warning in p4test.cpp<commit_after>/*
Copyright 2013-present Barefoot Networks, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <fstream>
#include <iostream>

#include "control-plane/p4RuntimeSerializer.h"
#include "ir/ir.h"
#include "ir/json_loader.h"
#include "lib/log.h"
#include "lib/error.h"
#include "lib/exceptions.h"
#include "lib/gc.h"
#include "lib/crash.h"
#include "lib/nullstream.h"
#include "frontends/common/parseInput.h"
#include "frontends/p4/evaluator/evaluator.h"
#include "frontends/p4/frontend.h"
#include "frontends/p4/toP4/toP4.h"
#include "midend.h"

class P4TestOptions : public CompilerOptions {
 public:
    bool parseOnly = false;
    bool validateOnly = false;
    P4TestOptions() {
        registerOption("--parse-only", nullptr,
                       [this](const char*) {
                           parseOnly = true;
                           return true; },
                       "only parse the P4 input, without any further processing");
        registerOption("--validate", nullptr,
                       [this](const char*) {
                           validateOnly = true;
                           return true;
                       },
                       "Validate the P4 input, running just the front-end");
     }
};

using P4TestContext = P4CContextWithOptions<P4TestOptions>;

static void log_dump(const IR::Node *node, const char *head) {
    if (node && LOGGING(1)) {
        if (head)
            std::cout << '+' << std::setw(strlen(head)+6) << std::setfill('-') << "+\n| "
                      << head << " |\n" << '+' << std::setw(strlen(head)+3) << "+" <<
                      std::endl << std::setfill(' ');
        if (LOGGING(2))
            dump(node);
        else
            std::cout << *node << std::endl; }
}

int main(int argc, char *const argv[]) {
    setup_gc_logging();
    setup_signals();

    AutoCompileContext autoP4TestContext(new P4TestContext);
    auto& options = P4TestContext::get().options();
    options.langVersion = CompilerOptions::FrontendVersion::P4_16;
    options.compilerVersion = "0.0.5";

    if (options.process(argc, argv) != nullptr)
        options.setInputFile();
    if (::errorCount() > 0)
        return 1;

    auto program = P4::parseP4File(options);
    auto hook = options.getDebugHook();

    if (program != nullptr && ::errorCount() == 0) {
        if (!options.parseOnly) {
            try {
                P4::FrontEnd fe;
                fe.addDebugHook(hook);
                program = fe.run(options, program);
            } catch (const Util::P4CExceptionBase &bug) {
                std::cerr << bug.what() << std::endl;
                return 1;
            }
        }
        log_dump(program, "Initial program");
        if (program != nullptr && ::errorCount() == 0) {
            if (!options.parseOnly && !options.validateOnly) {
                P4Test::MidEnd midEnd(options);
                midEnd.addDebugHook(hook);
#if 0
                /* doing this breaks the output until we get dump/undump of srcInfo */
                if (options.debugJson) {
                    std::stringstream tmp;
                    JSONGenerator gen(tmp);
                    gen << program;
                    JSONLoader loader(tmp);
                    loader >> program;
                }
#endif
                const IR::ToplevelBlock *top = nullptr;
                try {
                    top = midEnd.process(program);
                } catch (const Util::P4CExceptionBase &bug) {
                    std::cerr << bug.what() << std::endl;
                    return 1;
                }
                log_dump(program, "After midend");
                log_dump(top, "Top level block");
            }
            if (options.dumpJsonFile)
                JSONGenerator(*openFile(options.dumpJsonFile, true), true) << program << std::endl;
            if (options.debugJson) {
                std::stringstream ss1, ss2;
                JSONGenerator gen1(ss1), gen2(ss2);
                gen1 << program;

                const IR::Node* node = nullptr;
                JSONLoader loader(ss1);
                loader >> node;

                gen2 << node;
                if (ss1.str() != ss2.str()) {
                    error("json mismatch");
                    std::ofstream t1("t1.json"), t2("t2.json");
                    t1 << ss1.str() << std::flush;
                    t2 << ss2.str() << std::flush;
                    auto rv = system("json_diff t1.json t2.json");
                    if (rv != 0) ::warning("json_diff failed with code %1%", rv);
                }
            }
        }
    }

    P4::serializeP4RuntimeIfRequired(program, options);

    if (Log::verbose())
        std::cerr << "Done." << std::endl;
    return ::errorCount() > 0;
}
<|endoftext|>


<commit_before>#pragma once

#include "PythonHouseKeeper.h"

void FUnrealEnginePythonHouseKeeper::AddReferencedObjects(FReferenceCollector& InCollector)
{
    InCollector.AddReferencedObjects(PythonTrackedObjects);
}

FUnrealEnginePythonHouseKeeper *FUnrealEnginePythonHouseKeeper::Get()
{
    static FUnrealEnginePythonHouseKeeper *Singleton;
    if (!Singleton)
    {
        Singleton = new FUnrealEnginePythonHouseKeeper();
        // register a new delegate for the GC
#if ENGINE_MINOR_VERSION >= 18
        FCoreUObjectDelegates::GetPostGarbageCollect().AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate);
#else
        FCoreUObjectDelegates::PostGarbageCollect.AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate);
#endif
    }
    return Singleton;
}

void FUnrealEnginePythonHouseKeeper::RunGCDelegate()
{
    FScopePythonGIL gil;
    RunGC();
}

int32 FUnrealEnginePythonHouseKeeper::RunGC()
{
    int32 Garbaged = PyUObjectsGC();
    Garbaged += DelegatesGC();
    return Garbaged;
}

bool FUnrealEnginePythonHouseKeeper::IsValidPyUObject(ue_PyUObject *PyUObject)
{
    if (!PyUObject)
        return false;

    UObject *Object = PyUObject->ue_object;
    FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object);
    if (!Tracker)
    {
        return false;
    }

    if (!Tracker->Owner.IsValid())
        return false;

    return true;

}

void FUnrealEnginePythonHouseKeeper::TrackUObject(UObject *Object)
{
    FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object);
    if (!Tracker)
    {
        return;
    }
    if (Tracker->bPythonOwned)
        return;
    Tracker->bPythonOwned = true;
    // when a new ue_PyUObject spawns, it has a reference counting of two
    Py_DECREF(Tracker->PyUObject);
    Tracker->PyUObject->owned = 1;
    PythonTrackedObjects.Add(Object);
}

void FUnrealEnginePythonHouseKeeper::UntrackUObject(UObject *Object)
{
    PythonTrackedObjects.Remove(Object);
}

void FUnrealEnginePythonHouseKeeper::RegisterPyUObject(UObject *Object, ue_PyUObject *InPyUObject)
{
    UObjectPyMapping.Add(Object, FPythonUOjectTracker(Object, InPyUObject));
}

void FUnrealEnginePythonHouseKeeper::UnregisterPyUObject(UObject *Object)
{
    UObjectPyMapping.Remove(Object);
}

ue_PyUObject *FUnrealEnginePythonHouseKeeper::GetPyUObject(UObject *Object)
{
    FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object);
    if (!Tracker)
    {
        return nullptr;
    }

    if (!Tracker->Owner.IsValid(true))
    {
#if defined(UEPY_MEMORY_DEBUG)
        UE_LOG(LogPython, Warning, TEXT("DEFREF'ing UObject at %p (refcnt: %d)"), Object, Tracker->PyUObject->ob_base.ob_refcnt);
#endif
        if (!Tracker->bPythonOwned)
            Py_DECREF((PyObject *)Tracker->PyUObject);
        UnregisterPyUObject(Object);
        return nullptr;
}

    return Tracker->PyUObject;
}

uint32 FUnrealEnginePythonHouseKeeper::PyUObjectsGC()
{
    uint32 Garbaged = 0;
    TArray<UObject *> BrokenList;
    for (auto &UObjectPyItem : UObjectPyMapping)
    {
        UObject *Object = UObjectPyItem.Key;
        FPythonUOjectTracker &Tracker = UObjectPyItem.Value;
#if defined(UEPY_MEMORY_DEBUG)
        UE_LOG(LogPython, Warning, TEXT("Checking for UObject at %p"), Object);
#endif
        if (!Tracker.Owner.IsValid(true))
        {
#if defined(UEPY_MEMORY_DEBUG)
            UE_LOG(LogPython, Warning, TEXT("Removing UObject at %p (refcnt: %d)"), Object, Tracker.PyUObject->ob_base.ob_refcnt);
#endif
            BrokenList.Add(Object);
            Garbaged++;
    }
        else
        {
#if defined(UEPY_MEMORY_DEBUG)
            UE_LOG(LogPython, Error, TEXT("UObject at %p %s is in use"), Object, *Object->GetName());
#endif
}
    }

    for (UObject *Object : BrokenList)
    {
        FPythonUOjectTracker &Tracker = UObjectPyMapping[Object];
        if (!Tracker.bPythonOwned)
            Py_DECREF((PyObject *)Tracker.PyUObject);
        UnregisterPyUObject(Object);
    }

    return Garbaged;

}

int32 FUnrealEnginePythonHouseKeeper::DelegatesGC()
{
    int32 Garbaged = 0;
#if defined(UEPY_MEMORY_DEBUG)
    UE_LOG(LogPython, Display, TEXT("Garbage collecting %d UObject delegates"), PyDelegatesTracker.Num());
#endif
    for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i)
    {
        FPythonDelegateTracker &Tracker = PyDelegatesTracker[i];
        if (!Tracker.Owner.IsValid(true))
        {
            Tracker.Delegate->RemoveFromRoot();
            PyDelegatesTracker.RemoveAt(i);
            Garbaged++;
        }

    }

#if defined(UEPY_MEMORY_DEBUG)
    UE_LOG(LogPython, Display, TEXT("Garbage collecting %d Slate delegates"), PySlateDelegatesTracker.Num());
#endif

    for (int32 i = PySlateDelegatesTracker.Num() - 1; i >= 0; --i)
    {
        FPythonSWidgetDelegateTracker &Tracker = PySlateDelegatesTracker[i];
        if (!Tracker.Owner.IsValid())
        {
            PySlateDelegatesTracker.RemoveAt(i);
            Garbaged++;
        }

    }
    return Garbaged;
    }

UPythonDelegate *FUnrealEnginePythonHouseKeeper::FindDelegate(UObject *Owner, PyObject *PyCallable)
{
    for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i)
    {
        FPythonDelegateTracker &Tracker = PyDelegatesTracker[i];
        if (Tracker.Owner.Get() == Owner && Tracker.Delegate->UsesPyCallable(PyCallable))
            return Tracker.Delegate;
    }
    return nullptr;
}

UPythonDelegate *FUnrealEnginePythonHouseKeeper::NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature)
{
    UPythonDelegate *Delegate = NewObject<UPythonDelegate>();

    Delegate->AddToRoot();
    Delegate->SetPyCallable(PyCallable);
    Delegate->SetSignature(Signature);

    FPythonDelegateTracker Tracker(Delegate, Owner);
    PyDelegatesTracker.Add(Tracker);

    return Delegate;
}

TSharedRef<FPythonSlateDelegate> FUnrealEnginePythonHouseKeeper::NewSlateDelegate(TSharedRef<SWidget> Owner, PyObject *PyCallable)
{
    TSharedRef<FPythonSlateDelegate> Delegate = MakeShareable(new FPythonSlateDelegate());
    Delegate->SetPyCallable(PyCallable);

    FPythonSWidgetDelegateTracker Tracker(Delegate, Owner);
    PySlateDelegatesTracker.Add(Tracker);

    return Delegate;
}

TSharedRef<FPythonSlateDelegate> FUnrealEnginePythonHouseKeeper::NewDeferredSlateDelegate(PyObject *PyCallable)
{
    TSharedRef<FPythonSlateDelegate> Delegate = MakeShareable(new FPythonSlateDelegate());
    Delegate->SetPyCallable(PyCallable);

    return Delegate;
}

TSharedRef<FPythonSmartDelegate> FUnrealEnginePythonHouseKeeper::NewPythonSmartDelegate(PyObject *PyCallable)
{
    TSharedRef<FPythonSmartDelegate> Delegate = MakeShareable(new FPythonSmartDelegate());
    Delegate->SetPyCallable(PyCallable);

    PyStaticSmartDelegatesTracker.Add(Delegate);

    return Delegate;
}

void FUnrealEnginePythonHouseKeeper::TrackDeferredSlateDelegate(TSharedRef<FPythonSlateDelegate> Delegate, TSharedRef<SWidget> Owner)
{
    FPythonSWidgetDelegateTracker Tracker(Delegate, Owner);
    PySlateDelegatesTracker.Add(Tracker);
}

TSharedRef<FPythonSlateDelegate> FUnrealEnginePythonHouseKeeper::NewStaticSlateDelegate(PyObject *PyCallable)
{
    TSharedRef<FPythonSlateDelegate> Delegate = MakeShareable(new FPythonSlateDelegate());
    Delegate->SetPyCallable(PyCallable);

    PyStaticSlateDelegatesTracker.Add(Delegate);

    return Delegate;
}

<commit_msg>PythonHouseKeeper: Fix compile error: #pragma once in main file<commit_after>
#include "PythonHouseKeeper.h"

void FUnrealEnginePythonHouseKeeper::AddReferencedObjects(FReferenceCollector& InCollector)
{
    InCollector.AddReferencedObjects(PythonTrackedObjects);
}

FUnrealEnginePythonHouseKeeper *FUnrealEnginePythonHouseKeeper::Get()
{
    static FUnrealEnginePythonHouseKeeper *Singleton;
    if (!Singleton)
    {
        Singleton = new FUnrealEnginePythonHouseKeeper();
        // register a new delegate for the GC
#if ENGINE_MINOR_VERSION >= 18
        FCoreUObjectDelegates::GetPostGarbageCollect().AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate);
#else
        FCoreUObjectDelegates::PostGarbageCollect.AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate);
#endif
    }
    return Singleton;
}

void FUnrealEnginePythonHouseKeeper::RunGCDelegate()
{
    FScopePythonGIL gil;
    RunGC();
}

int32 FUnrealEnginePythonHouseKeeper::RunGC()
{
    int32 Garbaged = PyUObjectsGC();
    Garbaged += DelegatesGC();
    return Garbaged;
}

bool FUnrealEnginePythonHouseKeeper::IsValidPyUObject(ue_PyUObject *PyUObject)
{
    if (!PyUObject)
        return false;

    UObject *Object = PyUObject->ue_object;
    FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object);
    if (!Tracker)
    {
        return false;
    }

    if (!Tracker->Owner.IsValid())
        return false;

    return true;

}

void FUnrealEnginePythonHouseKeeper::TrackUObject(UObject *Object)
{
    FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object);
    if (!Tracker)
    {
        return;
    }
    if (Tracker->bPythonOwned)
        return;
    Tracker->bPythonOwned = true;
    // when a new ue_PyUObject spawns, it has a reference counting of two
    Py_DECREF(Tracker->PyUObject);
    Tracker->PyUObject->owned = 1;
    PythonTrackedObjects.Add(Object);
}

void FUnrealEnginePythonHouseKeeper::UntrackUObject(UObject *Object)
{
    PythonTrackedObjects.Remove(Object);
}

void FUnrealEnginePythonHouseKeeper::RegisterPyUObject(UObject *Object, ue_PyUObject *InPyUObject)
{
    UObjectPyMapping.Add(Object, FPythonUOjectTracker(Object, InPyUObject));
}

void FUnrealEnginePythonHouseKeeper::UnregisterPyUObject(UObject *Object)
{
    UObjectPyMapping.Remove(Object);
}

ue_PyUObject *FUnrealEnginePythonHouseKeeper::GetPyUObject(UObject *Object)
{
    FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object);
    if (!Tracker)
    {
        return nullptr;
    }

    if (!Tracker->Owner.IsValid(true))
    {
#if defined(UEPY_MEMORY_DEBUG)
        UE_LOG(LogPython, Warning, TEXT("DEFREF'ing UObject at %p (refcnt: %d)"), Object, Tracker->PyUObject->ob_base.ob_refcnt);
#endif
        if (!Tracker->bPythonOwned)
            Py_DECREF((PyObject *)Tracker->PyUObject);
        UnregisterPyUObject(Object);
        return nullptr;
}

    return Tracker->PyUObject;
}

uint32 FUnrealEnginePythonHouseKeeper::PyUObjectsGC()
{
    uint32 Garbaged = 0;
    TArray<UObject *> BrokenList;
    for (auto &UObjectPyItem : UObjectPyMapping)
    {
        UObject *Object = UObjectPyItem.Key;
        FPythonUOjectTracker &Tracker = UObjectPyItem.Value;
#if defined(UEPY_MEMORY_DEBUG)
        UE_LOG(LogPython, Warning, TEXT("Checking for UObject at %p"), Object);
#endif
        if (!Tracker.Owner.IsValid(true))
        {
#if defined(UEPY_MEMORY_DEBUG)
            UE_LOG(LogPython, Warning, TEXT("Removing UObject at %p (refcnt: %d)"), Object, Tracker.PyUObject->ob_base.ob_refcnt);
#endif
            BrokenList.Add(Object);
            Garbaged++;
    }
        else
        {
#if defined(UEPY_MEMORY_DEBUG)
            UE_LOG(LogPython, Error, TEXT("UObject at %p %s is in use"), Object, *Object->GetName());
#endif
}
    }

    for (UObject *Object : BrokenList)
    {
        FPythonUOjectTracker &Tracker = UObjectPyMapping[Object];
        if (!Tracker.bPythonOwned)
            Py_DECREF((PyObject *)Tracker.PyUObject);
        UnregisterPyUObject(Object);
    }

    return Garbaged;

}

int32 FUnrealEnginePythonHouseKeeper::DelegatesGC()
{
    int32 Garbaged = 0;
#if defined(UEPY_MEMORY_DEBUG)
    UE_LOG(LogPython, Display, TEXT("Garbage collecting %d UObject delegates"), PyDelegatesTracker.Num());
#endif
    for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i)
    {
        FPythonDelegateTracker &Tracker = PyDelegatesTracker[i];
        if (!Tracker.Owner.IsValid(true))
        {
            Tracker.Delegate->RemoveFromRoot();
            PyDelegatesTracker.RemoveAt(i);
            Garbaged++;
        }

    }

#if defined(UEPY_MEMORY_DEBUG)
    UE_LOG(LogPython, Display, TEXT("Garbage collecting %d Slate delegates"), PySlateDelegatesTracker.Num());
#endif

    for (int32 i = PySlateDelegatesTracker.Num() - 1; i >= 0; --i)
    {
        FPythonSWidgetDelegateTracker &Tracker = PySlateDelegatesTracker[i];
        if (!Tracker.Owner.IsValid())
        {
            PySlateDelegatesTracker.RemoveAt(i);
            Garbaged++;
        }

    }
    return Garbaged;
    }

UPythonDelegate *FUnrealEnginePythonHouseKeeper::FindDelegate(UObject *Owner, PyObject *PyCallable)
{
    for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i)
    {
        FPythonDelegateTracker &Tracker = PyDelegatesTracker[i];
        if (Tracker.Owner.Get() == Owner && Tracker.Delegate->UsesPyCallable(PyCallable))
            return Tracker.Delegate;
    }
    return nullptr;
}

UPythonDelegate *FUnrealEnginePythonHouseKeeper::NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature)
{
    UPythonDelegate *Delegate = NewObject<UPythonDelegate>();

    Delegate->AddToRoot();
    Delegate->SetPyCallable(PyCallable);
    Delegate->SetSignature(Signature);

    FPythonDelegateTracker Tracker(Delegate, Owner);
    PyDelegatesTracker.Add(Tracker);

    return Delegate;
}

TSharedRef<FPythonSlateDelegate> FUnrealEnginePythonHouseKeeper::NewSlateDelegate(TSharedRef<SWidget> Owner, PyObject *PyCallable)
{
    TSharedRef<FPythonSlateDelegate> Delegate = MakeShareable(new FPythonSlateDelegate());
    Delegate->SetPyCallable(PyCallable);

    FPythonSWidgetDelegateTracker Tracker(Delegate, Owner);
    PySlateDelegatesTracker.Add(Tracker);

    return Delegate;
}

TSharedRef<FPythonSlateDelegate> FUnrealEnginePythonHouseKeeper::NewDeferredSlateDelegate(PyObject *PyCallable)
{
    TSharedRef<FPythonSlateDelegate> Delegate = MakeShareable(new FPythonSlateDelegate());
    Delegate->SetPyCallable(PyCallable);

    return Delegate;
}

TSharedRef<FPythonSmartDelegate> FUnrealEnginePythonHouseKeeper::NewPythonSmartDelegate(PyObject *PyCallable)
{
    TSharedRef<FPythonSmartDelegate> Delegate = MakeShareable(new FPythonSmartDelegate());
    Delegate->SetPyCallable(PyCallable);

    PyStaticSmartDelegatesTracker.Add(Delegate);

    return Delegate;
}

void FUnrealEnginePythonHouseKeeper::TrackDeferredSlateDelegate(TSharedRef<FPythonSlateDelegate> Delegate, TSharedRef<SWidget> Owner)
{
    FPythonSWidgetDelegateTracker Tracker(Delegate, Owner);
    PySlateDelegatesTracker.Add(Tracker);
}

TSharedRef<FPythonSlateDelegate> FUnrealEnginePythonHouseKeeper::NewStaticSlateDelegate(PyObject *PyCallable)
{
    TSharedRef<FPythonSlateDelegate> Delegate = MakeShareable(new FPythonSlateDelegate());
    Delegate->SetPyCallable(PyCallable);

    PyStaticSlateDelegatesTracker.Add(Delegate);

    return Delegate;
}

<|endoftext|>


<commit_before>static char const libname[] = "LuaPackage";
#include "ExportThis.hpp"
#include "svc/FileSystem.hpp"
#include "Logfile.hpp"
#include "LuaUtils.hpp"
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/foreach.hpp>
#include <physfs.h>

static std::string const searchPath(
    std::string name, std::string path,
    char const* sep = ".", char const* rep = "/")
{
    using namespace boost::algorithm;
    if (sep)
        replace_all(name, sep, rep);
    replace_all(path, "?", name);

    std::vector<boost::iterator_range<std::string::iterator>> pelems;
    split(pelems, path, [](char c) { return c == ';'; });

    // hack: The C++ standard does not guarantee that std::string is zero
    //  terminated, only the return value of c_str() is. But even after calling
    //  it, this is not guaranted (or is it?) but any sane implementation of
    //  std::string will do it.
    path.c_str();
    BOOST_FOREACH (auto& elem, pelems) {
        if (elem.end() != path.end())
            *elem.end() = '\0';
        char const* filename = &*elem.begin();

        // Note that only the existence, not the actual readability of the file
        // is checked. Trying to open a file using PhysFS could be rather
        // expensive.
        if (PHYSFS_exists(filename))
            return std::string(elem.begin(), elem.end());
    }
    throw luaU::Error(
        "none of the files in path could be opened; searched: " + path);
}

static int findPackageInPhysFs(lua_State* L)
{
    char const* name = luaL_checkstring(L, 1);

    lua_getfield(L, lua_upvalueindex(1), "path");

    char const* path = lua_tostring(L, -1);
    if (!path)
        luaL_error(L, "\"package.path\" must be a string");

    try {
        std::string const filename = searchPath(name, path);
        luaU::load(L, filename); // push chunk
        lua_pushlstring(L, filename.c_str(), filename.size()); // push filename
    } catch (std::exception const& e) {
        lua_pushfstring(L, "\n\t%s", e.what());
        return 1;
    }
    return 2;
}

static int searchPathL(lua_State* L)
{
    char const *name = luaL_checkstring(L, 1),
               *path = luaL_checkstring(L, 2),
               *sep  = luaL_optstring  (L, 3, "."),
               *rep  = luaL_optstring  (L, 4, "/");
    try {
        searchPath(name, path, sep, rep);
    } catch (std::exception const& e) {
        lua_pushnil(L);
        lua_pushstring(L, e.what());
        return 2;
    }
    return 1;
}

static int loadfile(lua_State* L)
{
    char const *filename = lua_tostring  (L, 1),
               *mode     = luaL_optstring(L, 2, "bt");

    luaL_argcheck(L, filename, 1, "loading from stdin not supported");

    try {
         luaU::load(L, filename, mode);
    } catch (std::exception const& e) {
        lua_pushnil(L);
        lua_pushstring(L, e.what());
        return 2;
    }

    // set _ENV
    if (!lua_isnone(L, 3)) {
        lua_pushvalue(L, 3);
        lua_setupvalue(L, -1, 1);
    }
    return 1;
}

static int dofilecont (lua_State *L) {
    int oldtop;
    int const r = lua_getctx(L, &oldtop);
    assert(r == LUA_YIELD);
    return lua_gettop(L) - oldtop;
}

static int dofile(lua_State* L)
{
    // Note: this function (obviously) accepts the same parameters
    // as loadfile and not, as the Lua manual says, only a filename.
    // In addition, filename is not optional.
    int r = loadfile(L);
    if (r != 1 || !lua_isfunction(L, -1))
        return r;
    int const oldtop = lua_gettop(L) - 1;
    lua_callk(L, 0, LUA_MULTRET, oldtop, dofilecont);
    return lua_gettop(L) - oldtop;
}

void init(LuaVm& vm)
{
    lua_State* L = vm.L();

    LUAU_BALANCED_STACK(L);

    lua_pushcfunction(L, &loadfile);
    lua_setglobal(L, "loadfile");

    lua_pushcfunction(L, &dofile);
    lua_setglobal(L, "dofile");

    lua_getglobal(L, "package");
    if (lua_isnil(L, -1))
        return;

    lua_pushnil(L);
    lua_setfield(L, -2, "loadlib");

    lua_pushnil(L);
    lua_setfield(L, -2, "cpath");

    lua_pushcfunction(L, &searchPathL);
    lua_setfield(L, -2, "searchpath");

    lua_pushliteral(L,
        "lua/?.lua;" "lua/?.luac;"
        "lua/lib/?.lua;" "lua/lib/?.luac");
    lua_setfield(L, -2, "path");

    lua_getfield(L, -1, "searchers");

    // leave preload searcher as it is.

    // replace Lua searcher
    lua_pushvalue(L, -2); // package table --> upvalue #1
    lua_pushcclosure(L, &findPackageInPhysFs, 1);
    lua_rawseti(L, -2, 2);

    // block C and all-in-one searchers
    lua_pushnil(L);
    lua_rawseti(L, -2, 3);
    lua_pushnil(L);
    lua_rawseti(L, -2, 4);
}
<commit_msg>Fixed searchPath() only displaying the first tried file on error.<commit_after>static char const libname[] = "LuaPackage";
#include "ExportThis.hpp"
#include "svc/FileSystem.hpp"
#include "Logfile.hpp"
#include "LuaUtils.hpp"
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/foreach.hpp>
#include <physfs.h>

static std::string const searchPath(
    std::string name, std::string path,
    char const* sep = ".", char const* rep = "/")
{
    using namespace boost::algorithm;
    if (sep)
        replace_all(name, sep, rep);
    replace_all(path, "?", name);

    std::vector<boost::iterator_range<std::string::iterator>> pelems;
    split(pelems, path, [](char c) { return c == ';'; });

    // hack: The C++ standard does not guarantee that std::string is zero
    //  terminated, only the return value of c_str() is. But even after calling
    //  it, this is not guaranted (or is it?) but any sane implementation of
    //  std::string will do it.
    path.c_str();
    BOOST_FOREACH (auto& elem, pelems) {
        if (elem.end() != path.end())
            *elem.end() = '\0';
        char const* filename = &*elem.begin();

        // Note that only the existence, not the actual readability of the file
        // is checked. Trying to open a file using PhysFS could be rather
        // expensive.
        if (PHYSFS_exists(filename))
            return std::string(elem.begin(), elem.end());
    }
    replace_all(path, std::string(1, '\0'), ";"); // print all elements in error message
    throw luaU::Error(
        "none of the files in path could be opened:\n\t\t" + path);
}

static int findPackageInPhysFs(lua_State* L)
{
    char const* name = luaL_checkstring(L, 1);

    lua_getfield(L, lua_upvalueindex(1), "path");

    char const* path = lua_tostring(L, -1);
    if (!path)
        luaL_error(L, "\"package.path\" must be a string");

    try {
        std::string const filename = searchPath(name, path);
        luaU::load(L, filename); // push chunk
        lua_pushlstring(L, filename.c_str(), filename.size()); // push filename
    } catch (std::exception const& e) {
        lua_pushfstring(L, "\n\t%s", e.what());
        return 1;
    }
    return 2;
}

static int searchPathL(lua_State* L)
{
    char const *name = luaL_checkstring(L, 1),
               *path = luaL_checkstring(L, 2),
               *sep  = luaL_optstring  (L, 3, "."),
               *rep  = luaL_optstring  (L, 4, "/");
    try {
        searchPath(name, path, sep, rep);
    } catch (std::exception const& e) {
        lua_pushnil(L);
        lua_pushstring(L, e.what());
        return 2;
    }
    return 1;
}

static int loadfile(lua_State* L)
{
    char const *filename = lua_tostring  (L, 1),
               *mode     = luaL_optstring(L, 2, "bt");

    luaL_argcheck(L, filename, 1, "loading from stdin not supported");

    try {
         luaU::load(L, filename, mode);
    } catch (std::exception const& e) {
        lua_pushnil(L);
        lua_pushstring(L, e.what());
        return 2;
    }

    // set _ENV
    if (!lua_isnone(L, 3)) {
        lua_pushvalue(L, 3);
        lua_setupvalue(L, -1, 1);
    }
    return 1;
}

static int dofilecont (lua_State *L) {
    int oldtop;
    int const r = lua_getctx(L, &oldtop);
    assert(r == LUA_YIELD);
    return lua_gettop(L) - oldtop;
}

static int dofile(lua_State* L)
{
    // Note: this function (obviously) accepts the same parameters
    // as loadfile and not, as the Lua manual says, only a filename.
    // In addition, filename is not optional.
    int r = loadfile(L);
    if (r != 1 || !lua_isfunction(L, -1))
        return r;
    int const oldtop = lua_gettop(L) - 1;
    lua_callk(L, 0, LUA_MULTRET, oldtop, dofilecont);
    return lua_gettop(L) - oldtop;
}

void init(LuaVm& vm)
{
    lua_State* L = vm.L();

    LUAU_BALANCED_STACK(L);

    lua_pushcfunction(L, &loadfile);
    lua_setglobal(L, "loadfile");

    lua_pushcfunction(L, &dofile);
    lua_setglobal(L, "dofile");

    lua_getglobal(L, "package");
    if (lua_isnil(L, -1))
        return;

    lua_pushnil(L);
    lua_setfield(L, -2, "loadlib");

    lua_pushnil(L);
    lua_setfield(L, -2, "cpath");

    lua_pushcfunction(L, &searchPathL);
    lua_setfield(L, -2, "searchpath");

    lua_pushliteral(L,
        "lua/?.lua;" "lua/?.luac;"
        "lua/lib/?.lua;" "lua/lib/?.luac");
    lua_setfield(L, -2, "path");

    lua_getfield(L, -1, "searchers");

    // leave preload searcher as it is.

    // replace Lua searcher
    lua_pushvalue(L, -2); // package table --> upvalue #1
    lua_pushcclosure(L, &findPackageInPhysFs, 1);
    lua_rawseti(L, -2, 2);

    // block C and all-in-one searchers
    lua_pushnil(L);
    lua_rawseti(L, -2, 3);
    lua_pushnil(L);
    lua_rawseti(L, -2, 4);
}
<|endoftext|>


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

#include "config.h"
#include "core/platform/graphics/Font.h"

#include "core/platform/NotImplemented.h"
#include "core/platform/graphics/FloatRect.h"
#include "core/platform/graphics/GlyphBuffer.h"
#include "core/platform/graphics/GraphicsContext.h"
#include "core/platform/graphics/SimpleFontData.h"
#include "core/platform/graphics/harfbuzz/HarfBuzzShaper.h"

#include "SkPaint.h"
#include "SkTemplates.h"

#include "wtf/unicode/Unicode.h"

namespace WebCore {

bool Font::canReturnFallbackFontsForComplexText()
{
    return false;
}

bool Font::canExpandAroundIdeographsInComplexText()
{
    return false;
}

void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
                      const FloatPoint& point, const FloatRect& textRect) const {
    SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert

    const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
    SkScalar x = SkFloatToScalar(point.x());
    SkScalar y = SkFloatToScalar(point.y());

    // FIXME: text rendering speed:
    // Android has code in their WebCore fork to special case when the
    // GlyphBuffer has no advances other than the defaults. In that case the
    // text drawing can proceed faster. However, it's unclear when those
    // patches may be upstreamed to WebKit so we always use the slower path
    // here.
    const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
    SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs);
    SkPoint* pos = storage.get();
    SkPoint* vPosBegin = storage2.get();
    SkPoint* vPosEnd = storage3.get();

    bool isVertical = font->platformData().orientation() == Vertical;
    for (int i = 0; i < numGlyphs; i++) {
        SkScalar myWidth = SkFloatToScalar(adv[i].width());
        pos[i].set(x, y);
        if (isVertical) {
            vPosBegin[i].set(x + myWidth, y);
            vPosEnd[i].set(x + myWidth, y - myWidth);
        }
        x += myWidth;
        y += SkFloatToScalar(adv[i].height());
    }

    TextDrawingModeFlags textMode = gc->textDrawingMode();

    // We draw text up to two times (once for fill, once for stroke).
    if (textMode & TextModeFill) {
        SkPaint paint;
        gc->setupPaintForFilling(&paint);
        font->platformData().setupPaint(&paint);
        gc->adjustTextRenderMode(&paint);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

        if (isVertical) {
            SkPath path;
            for (int i = 0; i < numGlyphs; ++i) {
                path.reset();
                path.moveTo(vPosBegin[i]);
                path.lineTo(vPosEnd[i]);
                gc->drawTextOnPath(glyphs + i, 2, path, textRect, 0, paint);
            }
        } else
            gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint);
    }

    if ((textMode & TextModeStroke)
        && gc->strokeStyle() != NoStroke
        && gc->strokeThickness() > 0) {

        SkPaint paint;
        gc->setupPaintForStroking(&paint);
        font->platformData().setupPaint(&paint);
        gc->adjustTextRenderMode(&paint);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

        if (textMode & TextModeFill) {
            // If we also filled, we don't want to draw shadows twice.
            // See comment in FontChromiumWin.cpp::paintSkiaText() for more details.
            // Since we use the looper for shadows, we remove it (if any) now.
            paint.setLooper(0);
        }

        if (isVertical) {
            SkPath path;
            for (int i = 0; i < numGlyphs; ++i) {
                path.reset();
                path.moveTo(vPosBegin[i]);
                path.lineTo(vPosEnd[i]);
                gc->drawTextOnPath(glyphs + i, 2, path, textRect, 0, paint);
            }
        } else
            gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint);
    }
}

static void setupForTextPainting(SkPaint* paint, SkColor color)
{
    paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    paint->setColor(color);
}

void Font::drawComplexText(GraphicsContext* gc, const TextRunPaintInfo& runInfo, const FloatPoint& point) const
{
    if (!runInfo.run.length())
        return;

    TextDrawingModeFlags textMode = gc->textDrawingMode();
    bool fill = textMode & TextModeFill;
    bool stroke = (textMode & TextModeStroke)
        && gc->strokeStyle() != NoStroke
        && gc->strokeThickness() > 0;

    if (!fill && !stroke)
        return;

    SkPaint strokePaint, fillPaint;
    if (fill) {
        gc->setupPaintForFilling(&fillPaint);
        setupForTextPainting(&fillPaint, gc->fillColor().rgb());
    }
    if (stroke) {
        gc->setupPaintForStroking(&strokePaint);
        setupForTextPainting(&strokePaint, gc->strokeColor().rgb());
    }

    GlyphBuffer glyphBuffer;
    HarfBuzzShaper shaper(this, runInfo.run);
    shaper.setDrawRange(runInfo.from, runInfo.to);
    if (!shaper.shape(&glyphBuffer))
        return;
    FloatPoint adjustedPoint = shaper.adjustStartPoint(point);
    drawGlyphBuffer(gc, runInfo, glyphBuffer, adjustedPoint);
}

void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRunPaintInfo& /* runInfo */, const AtomicString& /* mark */, const FloatPoint& /* point */) const
{
    notImplemented();
}

float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const
{
    HarfBuzzShaper shaper(this, run);
    if (!shaper.shape())
        return 0;
    return shaper.totalWidth();
}

// Return the code point index for the given |x| offset into the text run.
int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
                                          bool includePartialGlyphs) const
{
    HarfBuzzShaper shaper(this, run);
    if (!shaper.shape())
        return 0;
    return shaper.offsetForPosition(xFloat);
}

// Return the rectangle for selecting the given range of code-points in the TextRun.
FloatRect Font::selectionRectForComplexText(const TextRun& run,
                                            const FloatPoint& point, int height,
                                            int from, int to) const
{
    HarfBuzzShaper shaper(this, run);
    if (!shaper.shape())
        return FloatRect();
    return shaper.selectionRect(point, height, from, to);
}

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

#include "config.h"
#include "core/platform/graphics/Font.h"

#include "core/platform/NotImplemented.h"
#include "core/platform/graphics/FloatRect.h"
#include "core/platform/graphics/GlyphBuffer.h"
#include "core/platform/graphics/GraphicsContext.h"
#include "core/platform/graphics/SimpleFontData.h"
#include "core/platform/graphics/harfbuzz/HarfBuzzShaper.h"

#include "SkPaint.h"
#include "SkTemplates.h"

#include "wtf/unicode/Unicode.h"

namespace WebCore {

bool Font::canReturnFallbackFontsForComplexText()
{
    return false;
}

bool Font::canExpandAroundIdeographsInComplexText()
{
    return false;
}

void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
                      const FloatPoint& point, const FloatRect& textRect) const {
    SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert

    const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
    SkScalar x = SkFloatToScalar(point.x());
    SkScalar y = SkFloatToScalar(point.y());

    // FIXME: text rendering speed:
    // Android has code in their WebCore fork to special case when the
    // GlyphBuffer has no advances other than the defaults. In that case the
    // text drawing can proceed faster. However, it's unclear when those
    // patches may be upstreamed to WebKit so we always use the slower path
    // here.
    const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
    SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs);
    SkPoint* pos = storage.get();
    SkPoint* vPosBegin = storage2.get();
    SkPoint* vPosEnd = storage3.get();

    bool isVertical = font->platformData().orientation() == Vertical;
    SkScalar verticalPosCompensation = isVertical ? SkFloatToScalar((font->fontMetrics().floatHeight() - font->fontMetrics().floatAscent()) / 2) : 0;
    for (int i = 0; i < numGlyphs; i++) {
        SkScalar myWidth = SkFloatToScalar(adv[i].width());
        pos[i].set(x, y);
        if (isVertical) {
            // In vertical mode, we need to align the left of ideographics to the vertical baseline.
            // (Note vertical/horizontal are in absolute orientation, that is, here x is vertical.)
            // However, when the glyph is drawn in drawTextOnPath(), the baseline is the horizontal path,
            // so the ideographics will look shifted to the bottom-right direction because the ascent is
            // applied vertically. Compensate the position so that ascent will look like to be applied
            // horizontally.
            SkScalar bottom = x + myWidth - verticalPosCompensation;
            SkScalar left = y + verticalPosCompensation;
            vPosBegin[i].set(bottom, left);
            vPosEnd[i].set(bottom, left - myWidth);
        }
        x += myWidth;
        y += SkFloatToScalar(adv[i].height());
    }

    TextDrawingModeFlags textMode = gc->textDrawingMode();

    // We draw text up to two times (once for fill, once for stroke).
    if (textMode & TextModeFill) {
        SkPaint paint;
        gc->setupPaintForFilling(&paint);
        font->platformData().setupPaint(&paint);
        gc->adjustTextRenderMode(&paint);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

        if (isVertical) {
            SkPath path;
            for (int i = 0; i < numGlyphs; ++i) {
                path.reset();
                path.moveTo(vPosBegin[i]);
                path.lineTo(vPosEnd[i]);
                gc->drawTextOnPath(glyphs + i, 2, path, textRect, 0, paint);
            }
        } else
            gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint);
    }

    if ((textMode & TextModeStroke)
        && gc->strokeStyle() != NoStroke
        && gc->strokeThickness() > 0) {

        SkPaint paint;
        gc->setupPaintForStroking(&paint);
        font->platformData().setupPaint(&paint);
        gc->adjustTextRenderMode(&paint);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

        if (textMode & TextModeFill) {
            // If we also filled, we don't want to draw shadows twice.
            // See comment in FontChromiumWin.cpp::paintSkiaText() for more details.
            // Since we use the looper for shadows, we remove it (if any) now.
            paint.setLooper(0);
        }

        if (isVertical) {
            SkPath path;
            for (int i = 0; i < numGlyphs; ++i) {
                path.reset();
                path.moveTo(vPosBegin[i]);
                path.lineTo(vPosEnd[i]);
                gc->drawTextOnPath(glyphs + i, 2, path, textRect, 0, paint);
            }
        } else
            gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint);
    }
}

static void setupForTextPainting(SkPaint* paint, SkColor color)
{
    paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    paint->setColor(color);
}

void Font::drawComplexText(GraphicsContext* gc, const TextRunPaintInfo& runInfo, const FloatPoint& point) const
{
    if (!runInfo.run.length())
        return;

    TextDrawingModeFlags textMode = gc->textDrawingMode();
    bool fill = textMode & TextModeFill;
    bool stroke = (textMode & TextModeStroke)
        && gc->strokeStyle() != NoStroke
        && gc->strokeThickness() > 0;

    if (!fill && !stroke)
        return;

    SkPaint strokePaint, fillPaint;
    if (fill) {
        gc->setupPaintForFilling(&fillPaint);
        setupForTextPainting(&fillPaint, gc->fillColor().rgb());
    }
    if (stroke) {
        gc->setupPaintForStroking(&strokePaint);
        setupForTextPainting(&strokePaint, gc->strokeColor().rgb());
    }

    GlyphBuffer glyphBuffer;
    HarfBuzzShaper shaper(this, runInfo.run);
    shaper.setDrawRange(runInfo.from, runInfo.to);
    if (!shaper.shape(&glyphBuffer))
        return;
    FloatPoint adjustedPoint = shaper.adjustStartPoint(point);
    drawGlyphBuffer(gc, runInfo, glyphBuffer, adjustedPoint);
}

void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRunPaintInfo& /* runInfo */, const AtomicString& /* mark */, const FloatPoint& /* point */) const
{
    notImplemented();
}

float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const
{
    HarfBuzzShaper shaper(this, run);
    if (!shaper.shape())
        return 0;
    return shaper.totalWidth();
}

// Return the code point index for the given |x| offset into the text run.
int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
                                          bool includePartialGlyphs) const
{
    HarfBuzzShaper shaper(this, run);
    if (!shaper.shape())
        return 0;
    return shaper.offsetForPosition(xFloat);
}

// Return the rectangle for selecting the given range of code-points in the TextRun.
FloatRect Font::selectionRectForComplexText(const TextRun& run,
                                            const FloatPoint& point, int height,
                                            int from, int to) const
{
    HarfBuzzShaper shaper(this, run);
    if (!shaper.shape())
        return FloatRect();
    return shaper.selectionRect(point, height, from, to);
}

} // namespace WebCore
<|endoftext|>


<commit_before>/* idmappingxmlsourcetests.cc			KPilot
**
** Copyright (C) 2007 by Bertjan Broeksema <b.broeksema@kdemail.net>
** Copyright (C) 2007 by Jason "vanRijn" Kasper <vr@movingparts.net>
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/
#include <QtTest>
#include <QtCore>

#include <idmappingxmlsource.h>
#include <options.h>

#include <KGlobal>
#include <KStandardDirs>

#include "qtest_kde.h"

class TestIDMappingXmlSource: public QObject
{
	Q_OBJECT

public:
	TestIDMappingXmlSource();

private slots:
	void testConstructor();
	void testLastSyncedDate();
	void testLastSyncedPC();
	void testMappings();
	void testSaveLoad();
	void cleanupTestCase();

private:
	void cleanDir();

	QString fUser;
	QString fConduit;
};

TestIDMappingXmlSource::TestIDMappingXmlSource() : fUser( "test-user" )
	, fConduit("test-conduit")
{
}

void TestIDMappingXmlSource::testConstructor()
{
	QString pathName = KGlobal::dirs()->saveLocation( "data",
		CSL1("kpilot/conduits/"));

	IDMappingXmlSource source( fUser, fConduit );

	QDir dir( pathName );
	QVERIFY( dir.exists( fUser ) );

	dir.cd( fUser );
	QVERIFY( dir.exists( CSL1( "mapping" ) ) );
}

void TestIDMappingXmlSource::testLastSyncedDate()
{
	QDateTime dt = QDateTime::currentDateTime();

	IDMappingXmlSource source( fUser, fConduit );
	source.setLastSyncedDate( dt );

	QDateTime dtSource = source.lastSyncedDate();
	QVERIFY( dt == dtSource );
}

void TestIDMappingXmlSource::testLastSyncedPC()
{
	QString pc( CSL1( "test-pc" ) );

	IDMappingXmlSource source( fUser, fConduit );
	source.setLastSyncedPC( pc );

	QString pcSource = source.lastSyncedPC();
	QVERIFY( pc == pcSource );
}

void TestIDMappingXmlSource::testMappings()
{
	IDMappingXmlSource source( fUser, fConduit );

	QMap<QString, QString> *mappings = source.mappings();
	mappings->insert( CSL1( "test-pc" ) , CSL1( "test-hh" ) );

	QMap<QString, QString> *mappings2 = source.mappings();

	QVERIFY( mappings2->size() == mappings->size() );

	QVERIFY( mappings2->value( CSL1( "test-pc" ) ) == CSL1( "test-hh" ) );
}

void TestIDMappingXmlSource::testSaveLoad()
{
	QDateTime dt = QDateTime::currentDateTime();
	// Correct msecs, these wont be saved and the test
	// dt == source2.lastSyncedDate() will fail.
	dt = dt.addMSecs( -dt.time().msec() );
	QString pc( CSL1( "test-pc" ) );

	IDMappingXmlSource source( fUser, fConduit );
	source.setLastSyncedDate( dt );
	source.setLastSyncedPC( pc );
	source.mappings()->insert( CSL1( "test-hh" ), CSL1( "test-pc" ) );
	source.mappings()->insert( CSL1( "test-hh2" ), CSL1( "test-pc2" ) );
	source.archivedRecords()->append( "test-pc2" );

	source.saveMapping();

	QString path = KGlobal::dirs()->saveLocation( "data",
		CSL1("kpilot/conduits/") );

	QDir dir( path );
	dir.cd( fUser + CSL1( "/mapping" ) );

	QVERIFY( dir.exists( fConduit + CSL1( "-mapping.xml" ) ) );

	IDMappingXmlSource source2( fUser, fConduit );
	source2.loadMapping();

	// There should be a backup now.
	QVERIFY( dir.exists( fConduit + CSL1( "-mapping.xml~" ) ) );

	QVERIFY( pc == source2.lastSyncedPC() );
	QVERIFY( dt == source2.lastSyncedDate() );
	QVERIFY( source2.mappings()->size() == 2 );
	QVERIFY( source2.mappings()->value( CSL1( "test-hh" ) )
		== CSL1( "test-pc" ) );
	QVERIFY( source2.mappings()->value( CSL1( "test-hh2" ) )
		== CSL1( "test-pc2" ) );

	QVERIFY( source2.archivedRecords()->size() == 1 );
	QVERIFY( source2.archivedRecords()->contains( CSL1( "test-pc2" ) ) );
}

void TestIDMappingXmlSource::cleanDir()
{
	QString pathName = KGlobal::dirs()->saveLocation( "data",
		CSL1("kpilot/conduits/"));

	QDir dir( pathName );
	dir.cd( fUser );
	dir.cd( CSL1( "mapping" ) );
	dir.remove( fConduit + CSL1( "-mapping.xml" ) );
	dir.remove(  fConduit + CSL1( "-mapping.xml~" ) );
	dir.remove(  fConduit + CSL1( "-mapping.xml.fail" ) );
	dir.cd( CSL1( ".." ) );
	dir.rmdir( CSL1( "mapping" ) );
	dir.cd( CSL1( ".." ) );
	dir.rmdir( fUser );
}

void TestIDMappingXmlSource::cleanupTestCase()
{
	cleanDir();
}

QTEST_KDEMAIN(TestIDMappingXmlSource, NoGUI)

#include "idmappinggxmlsourcetest.moc"
<commit_msg>Fix idmappingxmlsourcetest. vanRijn changed "~" suffix of backup file to  "-backup" but the test still assumed "~".<commit_after>/* idmappingxmlsourcetests.cc			KPilot
**
** Copyright (C) 2007 by Bertjan Broeksema <b.broeksema@kdemail.net>
** Copyright (C) 2007 by Jason "vanRijn" Kasper <vr@movingparts.net>
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/
#include <QtTest>
#include <QtCore>

#include <idmappingxmlsource.h>
#include <options.h>

#include <KGlobal>
#include <KStandardDirs>

#include "qtest_kde.h"

class TestIDMappingXmlSource: public QObject
{
	Q_OBJECT

public:
	TestIDMappingXmlSource();

private slots:
	void testConstructor();
	void testLastSyncedDate();
	void testLastSyncedPC();
	void testMappings();
	void testSaveLoad();
	void cleanupTestCase();

private:
	void cleanDir();

	QString fUser;
	QString fConduit;
};

TestIDMappingXmlSource::TestIDMappingXmlSource() : fUser( "test-user" )
	, fConduit("test-conduit")
{
}

void TestIDMappingXmlSource::testConstructor()
{
	QString pathName = KGlobal::dirs()->saveLocation( "data",
		CSL1("kpilot/conduits/"));

	IDMappingXmlSource source( fUser, fConduit );

	QDir dir( pathName );
	QVERIFY( dir.exists( fUser ) );

	dir.cd( fUser );
	QVERIFY( dir.exists( CSL1( "mapping" ) ) );
}

void TestIDMappingXmlSource::testLastSyncedDate()
{
	QDateTime dt = QDateTime::currentDateTime();

	IDMappingXmlSource source( fUser, fConduit );
	source.setLastSyncedDate( dt );

	QDateTime dtSource = source.lastSyncedDate();
	QVERIFY( dt == dtSource );
}

void TestIDMappingXmlSource::testLastSyncedPC()
{
	QString pc( CSL1( "test-pc" ) );

	IDMappingXmlSource source( fUser, fConduit );
	source.setLastSyncedPC( pc );

	QString pcSource = source.lastSyncedPC();
	QVERIFY( pc == pcSource );
}

void TestIDMappingXmlSource::testMappings()
{
	IDMappingXmlSource source( fUser, fConduit );

	QMap<QString, QString> *mappings = source.mappings();
	mappings->insert( CSL1( "test-pc" ) , CSL1( "test-hh" ) );

	QMap<QString, QString> *mappings2 = source.mappings();

	QVERIFY( mappings2->size() == mappings->size() );

	QVERIFY( mappings2->value( CSL1( "test-pc" ) ) == CSL1( "test-hh" ) );
}

void TestIDMappingXmlSource::testSaveLoad()
{
	QDateTime dt = QDateTime::currentDateTime();
	// Correct msecs, these wont be saved and the test
	// dt == source2.lastSyncedDate() will fail.
	dt = dt.addMSecs( -dt.time().msec() );
	QString pc( CSL1( "test-pc" ) );

	IDMappingXmlSource source( fUser, fConduit );
	source.setLastSyncedDate( dt );
	source.setLastSyncedPC( pc );
	source.mappings()->insert( CSL1( "test-hh" ), CSL1( "test-pc" ) );
	source.mappings()->insert( CSL1( "test-hh2" ), CSL1( "test-pc2" ) );
	source.archivedRecords()->append( "test-pc2" );

	source.saveMapping();

	QString path = KGlobal::dirs()->saveLocation( "data",
		CSL1("kpilot/conduits/") );

	QDir dir( path );
	dir.cd( fUser + CSL1( "/mapping" ) );

	QVERIFY( dir.exists( fConduit + CSL1( "-mapping.xml" ) ) );

	IDMappingXmlSource source2( fUser, fConduit );
	source2.loadMapping();

	// There should be a backup now.
	QVERIFY( dir.exists( fConduit + CSL1( "-mapping.xml-backup" ) ) );

	QVERIFY( pc == source2.lastSyncedPC() );
	QVERIFY( dt == source2.lastSyncedDate() );
	QVERIFY( source2.mappings()->size() == 2 );
	QVERIFY( source2.mappings()->value( CSL1( "test-hh" ) )
		== CSL1( "test-pc" ) );
	QVERIFY( source2.mappings()->value( CSL1( "test-hh2" ) )
		== CSL1( "test-pc2" ) );

	QVERIFY( source2.archivedRecords()->size() == 1 );
	QVERIFY( source2.archivedRecords()->contains( CSL1( "test-pc2" ) ) );
}

void TestIDMappingXmlSource::cleanDir()
{
	QString pathName = KGlobal::dirs()->saveLocation( "data",
		CSL1("kpilot/conduits/"));

	QDir dir( pathName );
	dir.cd( fUser );
	dir.cd( CSL1( "mapping" ) );
	dir.remove( fConduit + CSL1( "-mapping.xml" ) );
	dir.remove(  fConduit + CSL1( "-mapping.xml-backup" ) );
	dir.remove(  fConduit + CSL1( "-mapping.xml.fail" ) );
	dir.cd( CSL1( ".." ) );
	dir.rmdir( CSL1( "mapping" ) );
	dir.cd( CSL1( ".." ) );
	dir.rmdir( fUser );
}

void TestIDMappingXmlSource::cleanupTestCase()
{
	cleanDir();
}

QTEST_KDEMAIN(TestIDMappingXmlSource, NoGUI)

#include "idmappinggxmlsourcetest.moc"
<|endoftext|>


<commit_before><commit_msg>This implements the functions necessary for the task manager on Linux.<commit_after><|endoftext|>