<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ErrorBar.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: vg $ $Date: 2007-05-22 18:58:26 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "ErrorBar.hxx"
#include "macros.hxx"
#include "LineProperties.hxx"
#include "ContainerHelper.hxx"

#ifndef CHART_PROPERTYHELPER_HXX
#include "PropertyHelper.hxx"
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART2_ERRORBARSTYLE_HPP_
#include <com/sun/star/chart2/ErrorBarStyle.hpp>
#endif

#ifndef INCLUDED_RTL_MATH_HXX
#include <rtl/math.hxx>
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

using namespace ::com::sun::star;

using ::rtl::OUString;
using ::rtl::OUStringBuffer;
using ::com::sun::star::beans::Property;
using ::osl::MutexGuard;

namespace
{
static const OUString lcl_aServiceName(
    RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.chart2.ErrorBar" ));

enum
{
    PROP_ERROR_BAR_STYLE,
    PROP_ERROR_BAR_POS_ERROR,
    PROP_ERROR_BAR_NEG_ERROR,
    PROP_ERROR_BAR_WEIGHT,
    PROP_ERROR_BAR_SHOW_POS_ERROR,
    PROP_ERROR_BAR_SHOW_NEG_ERROR
};

void lcl_AddPropertiesToVector(
    ::std::vector< Property > & rOutProperties )
{
    rOutProperties.push_back(
        Property( C2U( "ErrorBarStyle" ),
                  PROP_ERROR_BAR_STYLE,
                  ::getCppuType( reinterpret_cast< const chart2::ErrorBarStyle * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));

    rOutProperties.push_back(
        Property( C2U( "PositiveError" ),
                  PROP_ERROR_BAR_POS_ERROR,
                  ::getCppuType( reinterpret_cast< const double * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));
    rOutProperties.push_back(
        Property( C2U( "NegativeError" ),
                  PROP_ERROR_BAR_NEG_ERROR,
                  ::getCppuType( reinterpret_cast< const double * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));

    rOutProperties.push_back(
        Property( C2U( "Weight" ),
                  PROP_ERROR_BAR_WEIGHT,
                  ::getCppuType( reinterpret_cast< const double * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));

    rOutProperties.push_back(
        Property( C2U( "ShowPositiveError" ),
                  PROP_ERROR_BAR_SHOW_POS_ERROR,
                  ::getBooleanCppuType(),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));
    rOutProperties.push_back(
        Property( C2U( "ShowNegativeError" ),
                  PROP_ERROR_BAR_SHOW_NEG_ERROR,
                  ::getBooleanCppuType(),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));
}

void lcl_AddDefaultsToMap(
    ::chart::tPropertyValueMap & rOutMap )
{
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_STYLE ));
    rOutMap[ PROP_ERROR_BAR_STYLE ] =
        uno::makeAny( chart2::ErrorBarStyle_NONE );
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_POS_ERROR ));
    rOutMap[ PROP_ERROR_BAR_POS_ERROR ] =
        uno::makeAny( 0.0 );
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_NEG_ERROR ));
    rOutMap[ PROP_ERROR_BAR_NEG_ERROR ] =
        uno::makeAny( 0.0 );
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_WEIGHT ));
    rOutMap[ PROP_ERROR_BAR_WEIGHT ] =
        uno::makeAny( 1.0 );
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_SHOW_POS_ERROR ));
    rOutMap[ PROP_ERROR_BAR_SHOW_POS_ERROR ] =
        uno::makeAny( sal_True );
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_SHOW_NEG_ERROR ));
    rOutMap[ PROP_ERROR_BAR_SHOW_NEG_ERROR ] =
        uno::makeAny( sal_True );
}

const uno::Sequence< Property > & lcl_GetPropertySequence()
{
    static uno::Sequence< Property > aPropSeq;

    // /--
    MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( 0 == aPropSeq.getLength() )
    {
        // get properties
        ::std::vector< ::com::sun::star::beans::Property > aProperties;
        lcl_AddPropertiesToVector( aProperties );
        ::chart::LineProperties::AddPropertiesToVector( aProperties );

        // and sort them for access via bsearch
        ::std::sort( aProperties.begin(), aProperties.end(),
                     ::chart::PropertyNameLess() );

        // transfer result to static Sequence
        aPropSeq = ::chart::ContainerHelper::ContainerToSequence( aProperties );
    }

    return aPropSeq;
}

::cppu::IPropertyArrayHelper & lcl_getInfoHelper()
{
    static ::cppu::OPropertyArrayHelper aArrayHelper(
        lcl_GetPropertySequence(),
        /* bSorted = */ sal_True );

    return aArrayHelper;
}

} // anonymous namespace

namespace chart
{

ErrorBar::ErrorBar(
    uno::Reference< uno::XComponentContext > const & xContext ) :
        ::property::OPropertySet( m_aMutex ),
    m_xContext( xContext ),
    m_xModifyEventForwarder( new ModifyListenerHelper::ModifyEventForwarder( m_aMutex ))
{}

ErrorBar::ErrorBar( const ErrorBar & rOther ) :
        ::property::OPropertySet( rOther, m_aMutex ),
    m_xContext( rOther.m_xContext ),
    m_xModifyEventForwarder( new ModifyListenerHelper::ModifyEventForwarder( m_aMutex ))
{}

ErrorBar::~ErrorBar()
{}

uno::Reference< util::XCloneable > SAL_CALL ErrorBar::createClone()
    throw (uno::RuntimeException)
{
    return uno::Reference< util::XCloneable >( new ErrorBar( *this ));
}

// ================================================================================

// ____ OPropertySet ____
uno::Any ErrorBar::GetDefaultValue( sal_Int32 nHandle ) const
    throw(beans::UnknownPropertyException)
{
    static tPropertyValueMap aStaticDefaults;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( 0 == aStaticDefaults.size() )
    {
        // initialize defaults
        lcl_AddDefaultsToMap( aStaticDefaults );
        LineProperties::AddDefaultsToMap( aStaticDefaults );
    }

    tPropertyValueMap::const_iterator aFound(
        aStaticDefaults.find( nHandle ));

    if( aFound == aStaticDefaults.end())
        return uno::Any();

    return (*aFound).second;
    // \--
}

::cppu::IPropertyArrayHelper & SAL_CALL ErrorBar::getInfoHelper()
{
    return lcl_getInfoHelper();
}

// ____ XPropertySet ____
uno::Reference< beans::XPropertySetInfo > SAL_CALL
    ErrorBar::getPropertySetInfo()
    throw (uno::RuntimeException)
{
    static uno::Reference< beans::XPropertySetInfo > xInfo;

    // /--
    MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( !xInfo.is())
    {
        xInfo = ::cppu::OPropertySetHelper::createPropertySetInfo(
            getInfoHelper());
    }

    return xInfo;
    // \--
}

// ____ XModifyBroadcaster ____
void SAL_CALL ErrorBar::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
    throw (uno::RuntimeException)
{
    try
    {
        uno::Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW );
        xBroadcaster->addModifyListener( aListener );
    }
    catch( const uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }
}

void SAL_CALL ErrorBar::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
    throw (uno::RuntimeException)
{
    try
    {
        uno::Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW );
        xBroadcaster->removeModifyListener( aListener );
    }
    catch( const uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }
}

// ____ XModifyListener ____
void SAL_CALL ErrorBar::modified( const lang::EventObject& aEvent )
    throw (uno::RuntimeException)
{
    m_xModifyEventForwarder->modified( aEvent );
}

// ____ XEventListener (base of XModifyListener) ____
void SAL_CALL ErrorBar::disposing( const lang::EventObject& Source )
    throw (uno::RuntimeException)
{
    // nothing
}

// ____ OPropertySet ____
void ErrorBar::firePropertyChangeEvent()
{
    fireModifyEvent();
}

void ErrorBar::fireModifyEvent()
{
    m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this )));
}

// ================================================================================

uno::Sequence< ::rtl::OUString > ErrorBar::getSupportedServiceNames_Static()
{
    uno::Sequence< ::rtl::OUString > aServices( 2 );
    aServices[ 0 ] = lcl_aServiceName;
    aServices[ 1 ] = C2U( "com.sun.star.chart2.ErrorBar" );
    return aServices;
}

// implement XServiceInfo methods basing upon getSupportedServiceNames_Static
APPHELPER_XSERVICEINFO_IMPL( ErrorBar, lcl_aServiceName );

// needed by MSC compiler
using impl::ErrorBar_Base;

IMPLEMENT_FORWARD_XINTERFACE2( ErrorBar, ErrorBar_Base, OPropertySet )
IMPLEMENT_FORWARD_XTYPEPROVIDER2( ErrorBar, ErrorBar_Base, OPropertySet )

} //  namespace chart
<commit_msg>INTEGRATION: CWS chart07 (1.6.12); FILE MERGED 2007/07/10 12:56:19 bm 1.6.12.2: #i69281# warnings removed 2007/07/04 16:47:59 bm 1.6.12.1: warnings removed<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ErrorBar.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2007-07-25 08:57:00 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "ErrorBar.hxx"
#include "macros.hxx"
#include "LineProperties.hxx"
#include "ContainerHelper.hxx"

#ifndef CHART_PROPERTYHELPER_HXX
#include "PropertyHelper.hxx"
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART2_ERRORBARSTYLE_HPP_
#include <com/sun/star/chart2/ErrorBarStyle.hpp>
#endif

#ifndef INCLUDED_RTL_MATH_HXX
#include <rtl/math.hxx>
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

using namespace ::com::sun::star;

using ::rtl::OUString;
using ::rtl::OUStringBuffer;
using ::com::sun::star::beans::Property;
using ::osl::MutexGuard;

namespace
{
static const OUString lcl_aServiceName(
    RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.chart2.ErrorBar" ));

enum
{
    PROP_ERROR_BAR_STYLE,
    PROP_ERROR_BAR_POS_ERROR,
    PROP_ERROR_BAR_NEG_ERROR,
    PROP_ERROR_BAR_WEIGHT,
    PROP_ERROR_BAR_SHOW_POS_ERROR,
    PROP_ERROR_BAR_SHOW_NEG_ERROR
};

void lcl_AddPropertiesToVector(
    ::std::vector< Property > & rOutProperties )
{
    rOutProperties.push_back(
        Property( C2U( "ErrorBarStyle" ),
                  PROP_ERROR_BAR_STYLE,
                  ::getCppuType( reinterpret_cast< const chart2::ErrorBarStyle * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));

    rOutProperties.push_back(
        Property( C2U( "PositiveError" ),
                  PROP_ERROR_BAR_POS_ERROR,
                  ::getCppuType( reinterpret_cast< const double * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));
    rOutProperties.push_back(
        Property( C2U( "NegativeError" ),
                  PROP_ERROR_BAR_NEG_ERROR,
                  ::getCppuType( reinterpret_cast< const double * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));

    rOutProperties.push_back(
        Property( C2U( "Weight" ),
                  PROP_ERROR_BAR_WEIGHT,
                  ::getCppuType( reinterpret_cast< const double * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));

    rOutProperties.push_back(
        Property( C2U( "ShowPositiveError" ),
                  PROP_ERROR_BAR_SHOW_POS_ERROR,
                  ::getBooleanCppuType(),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));
    rOutProperties.push_back(
        Property( C2U( "ShowNegativeError" ),
                  PROP_ERROR_BAR_SHOW_NEG_ERROR,
                  ::getBooleanCppuType(),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));
}

void lcl_AddDefaultsToMap(
    ::chart::tPropertyValueMap & rOutMap )
{
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_STYLE ));
    rOutMap[ PROP_ERROR_BAR_STYLE ] =
        uno::makeAny( chart2::ErrorBarStyle_NONE );
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_POS_ERROR ));
    rOutMap[ PROP_ERROR_BAR_POS_ERROR ] =
        uno::makeAny( 0.0 );
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_NEG_ERROR ));
    rOutMap[ PROP_ERROR_BAR_NEG_ERROR ] =
        uno::makeAny( 0.0 );
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_WEIGHT ));
    rOutMap[ PROP_ERROR_BAR_WEIGHT ] =
        uno::makeAny( 1.0 );
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_SHOW_POS_ERROR ));
    rOutMap[ PROP_ERROR_BAR_SHOW_POS_ERROR ] =
        uno::makeAny( sal_True );
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_ERROR_BAR_SHOW_NEG_ERROR ));
    rOutMap[ PROP_ERROR_BAR_SHOW_NEG_ERROR ] =
        uno::makeAny( sal_True );
}

const uno::Sequence< Property > & lcl_GetPropertySequence()
{
    static uno::Sequence< Property > aPropSeq;

    // /--
    MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( 0 == aPropSeq.getLength() )
    {
        // get properties
        ::std::vector< ::com::sun::star::beans::Property > aProperties;
        lcl_AddPropertiesToVector( aProperties );
        ::chart::LineProperties::AddPropertiesToVector( aProperties );

        // and sort them for access via bsearch
        ::std::sort( aProperties.begin(), aProperties.end(),
                     ::chart::PropertyNameLess() );

        // transfer result to static Sequence
        aPropSeq = ::chart::ContainerHelper::ContainerToSequence( aProperties );
    }

    return aPropSeq;
}

::cppu::IPropertyArrayHelper & lcl_getInfoHelper()
{
    static ::cppu::OPropertyArrayHelper aArrayHelper(
        lcl_GetPropertySequence(),
        /* bSorted = */ sal_True );

    return aArrayHelper;
}

} // anonymous namespace

namespace chart
{

ErrorBar::ErrorBar(
    uno::Reference< uno::XComponentContext > const & xContext ) :
        ::property::OPropertySet( m_aMutex ),
    m_xContext( xContext ),
    m_xModifyEventForwarder( new ModifyListenerHelper::ModifyEventForwarder( m_aMutex ))
{}

ErrorBar::ErrorBar( const ErrorBar & rOther ) :
        MutexContainer(),
        impl::ErrorBar_Base(),
        ::property::OPropertySet( rOther, m_aMutex ),
    m_xContext( rOther.m_xContext ),
    m_xModifyEventForwarder( new ModifyListenerHelper::ModifyEventForwarder( m_aMutex ))
{}

ErrorBar::~ErrorBar()
{}

uno::Reference< util::XCloneable > SAL_CALL ErrorBar::createClone()
    throw (uno::RuntimeException)
{
    return uno::Reference< util::XCloneable >( new ErrorBar( *this ));
}

// ================================================================================

// ____ OPropertySet ____
uno::Any ErrorBar::GetDefaultValue( sal_Int32 nHandle ) const
    throw(beans::UnknownPropertyException)
{
    static tPropertyValueMap aStaticDefaults;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( 0 == aStaticDefaults.size() )
    {
        // initialize defaults
        lcl_AddDefaultsToMap( aStaticDefaults );
        LineProperties::AddDefaultsToMap( aStaticDefaults );
    }

    tPropertyValueMap::const_iterator aFound(
        aStaticDefaults.find( nHandle ));

    if( aFound == aStaticDefaults.end())
        return uno::Any();

    return (*aFound).second;
    // \--
}

::cppu::IPropertyArrayHelper & SAL_CALL ErrorBar::getInfoHelper()
{
    return lcl_getInfoHelper();
}

// ____ XPropertySet ____
uno::Reference< beans::XPropertySetInfo > SAL_CALL
    ErrorBar::getPropertySetInfo()
    throw (uno::RuntimeException)
{
    static uno::Reference< beans::XPropertySetInfo > xInfo;

    // /--
    MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( !xInfo.is())
    {
        xInfo = ::cppu::OPropertySetHelper::createPropertySetInfo(
            getInfoHelper());
    }

    return xInfo;
    // \--
}

// ____ XModifyBroadcaster ____
void SAL_CALL ErrorBar::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
    throw (uno::RuntimeException)
{
    try
    {
        uno::Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW );
        xBroadcaster->addModifyListener( aListener );
    }
    catch( const uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }
}

void SAL_CALL ErrorBar::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
    throw (uno::RuntimeException)
{
    try
    {
        uno::Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW );
        xBroadcaster->removeModifyListener( aListener );
    }
    catch( const uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }
}

// ____ XModifyListener ____
void SAL_CALL ErrorBar::modified( const lang::EventObject& aEvent )
    throw (uno::RuntimeException)
{
    m_xModifyEventForwarder->modified( aEvent );
}

// ____ XEventListener (base of XModifyListener) ____
void SAL_CALL ErrorBar::disposing( const lang::EventObject& /* Source */ )
    throw (uno::RuntimeException)
{
    // nothing
}

// ____ OPropertySet ____
void ErrorBar::firePropertyChangeEvent()
{
    fireModifyEvent();
}

void ErrorBar::fireModifyEvent()
{
    m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this )));
}

// ================================================================================

uno::Sequence< ::rtl::OUString > ErrorBar::getSupportedServiceNames_Static()
{
    uno::Sequence< ::rtl::OUString > aServices( 2 );
    aServices[ 0 ] = lcl_aServiceName;
    aServices[ 1 ] = C2U( "com.sun.star.chart2.ErrorBar" );
    return aServices;
}

// implement XServiceInfo methods basing upon getSupportedServiceNames_Static
APPHELPER_XSERVICEINFO_IMPL( ErrorBar, lcl_aServiceName );

// needed by MSC compiler
using impl::ErrorBar_Base;

IMPLEMENT_FORWARD_XINTERFACE2( ErrorBar, ErrorBar_Base, OPropertySet )
IMPLEMENT_FORWARD_XTYPEPROVIDER2( ErrorBar, ErrorBar_Base, OPropertySet )

} //  namespace chart
<|endoftext|>


<commit_before>// Copyright 2004-present Facebook. All Rights Reserved.

#include "osquery/scheduler.h"

#include <climits>
#include <ctime>

#include <glog/logging.h>

#include "osquery/config.h"
#include "osquery/core.h"
#include "osquery/database.h"
#include "osquery/logger.h"

#ifdef OSQUERY_TEST_DAEMON
// if we're testing the daemon, set the time between each "minute" to be one
// second so that we see results faster
#define SECONDS_IN_A_MINUTE 1
#else
// in production, a minute is 60 seconds long
#define SECONDS_IN_A_MINUTE 60
#endif

using namespace osquery::config;
namespace core = osquery::core;
namespace db = osquery::db;
namespace logger = osquery::logger;

namespace osquery {
namespace scheduler {

void launchQueries(const osquery::config::scheduledQueries_t& queries,
                   const int64_t& minute) {
  LOG(INFO) << "launchQueries: " << minute;
  for (const auto& query : queries) {
    if (minute % query.interval == 0) {
      LOG(INFO) << "executing query: " << query.query;
      int unix_time = std::time(0);
      int err;
      auto query_results = core::aggregateQuery(query.query, err);
      if (err != 0) {
        LOG(ERROR) << "error executing query: " << query.query;
        continue;
      }
      auto dbQuery = db::Query(query);
      db::DiffResults diff_results;
      auto status =
          dbQuery.addNewResults(query_results, diff_results, unix_time);
      if (!status.ok()) {
        LOG(ERROR)
            << "error adding new results to database: " << status.toString();
        continue;
      }

      if (diff_results.added.size() > 0 || diff_results.removed.size() > 0) {
        VLOG(1) << "Results found for query: \"" << query.query << "\"";
        db::ScheduledQueryLogItem item;
        item.diffResults = diff_results;
        item.name = query.name;
        item.hostname = osquery::core::getHostname();
        item.unixTime = osquery::core::getUnixTime();
        item.calendarTime = osquery::core::getAsciiTime();
        auto s = logger::logScheduledQueryLogItem(item);
        if (!s.ok()) {
          LOG(ERROR) << "Error logging the results of query \"" << query.query
                     << "\""
                     << ": " << s.toString();
        }
      }
    }
  }
}

void initialize() {
  DLOG(INFO) << "osquery::scheduler::initialize";
  time_t t = time(0);
  struct tm* local = localtime(&t);
  unsigned long int minute = local->tm_min;
  auto cfg = Config::getInstance();
#ifdef OSQUERY_TEST_DAEMON
  // if we're testing the daemon, only iterate through 15 "minutes"
  static unsigned long int stop_at = minute + 15;
#else
  // if this is production, count forever
  static unsigned long int stop_at = LONG_MAX;
#endif
  for (; minute <= stop_at; ++minute) {
    launchQueries(cfg->getScheduledQueries(), minute);
    sleep(SECONDS_IN_A_MINUTE);
  }
}
}
}
<commit_msg>query time count is a ulong not a long<commit_after>// Copyright 2004-present Facebook. All Rights Reserved.

#include "osquery/scheduler.h"

#include <climits>
#include <ctime>

#include <glog/logging.h>

#include "osquery/config.h"
#include "osquery/core.h"
#include "osquery/database.h"
#include "osquery/logger.h"

#ifdef OSQUERY_TEST_DAEMON
// if we're testing the daemon, set the time between each "minute" to be one
// second so that we see results faster
#define SECONDS_IN_A_MINUTE 1
#else
// in production, a minute is 60 seconds long
#define SECONDS_IN_A_MINUTE 60
#endif

using namespace osquery::config;
namespace core = osquery::core;
namespace db = osquery::db;
namespace logger = osquery::logger;

namespace osquery {
namespace scheduler {

void launchQueries(const osquery::config::scheduledQueries_t& queries,
                   const int64_t& minute) {
  LOG(INFO) << "launchQueries: " << minute;
  for (const auto& query : queries) {
    if (minute % query.interval == 0) {
      LOG(INFO) << "executing query: " << query.query;
      int unix_time = std::time(0);
      int err;
      auto query_results = core::aggregateQuery(query.query, err);
      if (err != 0) {
        LOG(ERROR) << "error executing query: " << query.query;
        continue;
      }
      auto dbQuery = db::Query(query);
      db::DiffResults diff_results;
      auto status =
          dbQuery.addNewResults(query_results, diff_results, unix_time);
      if (!status.ok()) {
        LOG(ERROR)
            << "error adding new results to database: " << status.toString();
        continue;
      }

      if (diff_results.added.size() > 0 || diff_results.removed.size() > 0) {
        VLOG(1) << "Results found for query: \"" << query.query << "\"";
        db::ScheduledQueryLogItem item;
        item.diffResults = diff_results;
        item.name = query.name;
        item.hostname = osquery::core::getHostname();
        item.unixTime = osquery::core::getUnixTime();
        item.calendarTime = osquery::core::getAsciiTime();
        auto s = logger::logScheduledQueryLogItem(item);
        if (!s.ok()) {
          LOG(ERROR) << "Error logging the results of query \"" << query.query
                     << "\""
                     << ": " << s.toString();
        }
      }
    }
  }
}

void initialize() {
  DLOG(INFO) << "osquery::scheduler::initialize";
  time_t t = time(0);
  struct tm* local = localtime(&t);
  unsigned long int minute = local->tm_min;
  auto cfg = Config::getInstance();
#ifdef OSQUERY_TEST_DAEMON
  // if we're testing the daemon, only iterate through 15 "minutes"
  static unsigned long int stop_at = minute + 15;
#else
  // if this is production, count forever
  static unsigned long int stop_at = ULONG_MAX;
#endif
  for (; minute <= stop_at; ++minute) {
    launchQueries(cfg->getScheduledQueries(), minute);
    sleep(SECONDS_IN_A_MINUTE);
  }
}
}
}
<|endoftext|>


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

#include "chrome/browser/net/preconnect.h"

#include "base/histogram.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "net/base/host_port_pair.h"
#include "net/http/http_network_session.h"
#include "net/http/http_transaction_factory.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h"

namespace chrome_browser_net {

// static
bool Preconnect::preconnect_despite_proxy_ = false;

Preconnect::~Preconnect() {
  if (!handle_.is_initialized())
    return;
  DCHECK(motivation_ == UrlInfo::LEARNED_REFERAL_MOTIVATED ||
         motivation_ == UrlInfo::OMNIBOX_MOTIVATED);
  if (motivation_ == UrlInfo::OMNIBOX_MOTIVATED)
    handle_.socket()->SetOmniboxSpeculation();
  else
    handle_.socket()->SetSubresourceSpeculation();
  handle_.Reset();
}

// static
void Preconnect::PreconnectOnUIThread(const GURL& url,
    UrlInfo::ResolutionMotivation motivation) {
  // Prewarm connection to Search URL.
  ChromeThread::PostTask(
      ChromeThread::IO,
      FROM_HERE,
      NewRunnableFunction(Preconnect::PreconnectOnIOThread, url, motivation));
  return;
}

enum ProxyStatus {
  PROXY_STATUS_IGNORED,
  PROXY_UNINITIALIZED,
  PROXY_NOT_USED,
  PROXY_PAC_RESOLVER,
  PROXY_HAS_RULES,
  PROXY_MAX,
};

static void HistogramPreconnectStatus(ProxyStatus status) {
  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectProxyStatus", status, PROXY_MAX);
}

// static
void Preconnect::PreconnectOnIOThread(const GURL& url,
    UrlInfo::ResolutionMotivation motivation) {
  scoped_refptr<Preconnect> preconnect = new Preconnect(motivation);
  // TODO(jar): Should I use PostTask for LearnedSubresources to delay the
  // preconnection a tad?
  preconnect->Connect(url);
}

void Preconnect::Connect(const GURL& url) {
  URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
  if (!getter)
    return;
  if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
    LOG(DFATAL) << "This must be run only on the IO thread.";
    return;
  }

  AddRef();  // Stay alive until socket is available.

  URLRequestContext* context = getter->GetURLRequestContext();

  if (preconnect_despite_proxy_) {
    HistogramPreconnectStatus(PROXY_STATUS_IGNORED);
  } else {
    // Currently we avoid all preconnects if there is a proxy configuration.
    net::ProxyService* proxy_service = context->proxy_service();
    if (!proxy_service->config_has_been_initialized()) {
      HistogramPreconnectStatus(PROXY_UNINITIALIZED);
    } else {
      if (proxy_service->config().MayRequirePACResolver()) {
        HistogramPreconnectStatus(PROXY_PAC_RESOLVER);
        return;
      }
      if (!proxy_service->config().proxy_rules().empty()) {
        HistogramPreconnectStatus(PROXY_HAS_RULES);
        return;
      }
      HistogramPreconnectStatus(PROXY_NOT_USED);
    }
  }

  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation_,
                            UrlInfo::MAX_MOTIVATED);

  net::HttpTransactionFactory* factory = context->http_transaction_factory();
  net::HttpNetworkSession* session = factory->GetSession();

  scoped_refptr<net::TCPSocketParams> tcp_params =
      new net::TCPSocketParams(url.host(), url.EffectiveIntPort(), net::LOW,
                               GURL(), false);

  net::HostPortPair endpoint(url.host(), url.EffectiveIntPort());
  std::string group_name = endpoint.ToString();

  // It almost doesn't matter whether we use net::LOWEST or net::HIGHEST
  // priority here, as we won't make a request, and will surrender the created
  // socket to the pool as soon as we can.  However, we would like to mark the
  // speculative socket as such, and IF we use a net::LOWEST priority, and if
  // a navigation asked for a socket (after us) then it would get our socket,
  // and we'd get its later-arriving socket, which might make us record that
  // the speculation didn't help :-/.  By using net::HIGHEST, we ensure that
  // a socket is given to us if "we asked first" and this allows us to mark it
  // as speculative, and better detect stats (if it gets used).
  // TODO(jar): histogram to see how often we accidentally use a previously-
  // unused socket, when a previously used socket was available.
  net::RequestPriority priority = net::HIGHEST;

  if (url.SchemeIs("https")) {
    group_name = StringPrintf("ssl/%s", group_name.c_str());

    net::SSLConfig ssl_config;
    session->ssl_config_service()->GetSSLConfig(&ssl_config);
    // All preconnects should be for main pages.
    ssl_config.verify_ev_cert = true;

    scoped_refptr<net::SSLSocketParams> ssl_params =
        new net::SSLSocketParams(tcp_params, NULL, NULL,
                                 net::ProxyServer::SCHEME_DIRECT,
                                 url.HostNoBrackets(), ssl_config,
                                 0, false, false);

    const scoped_refptr<net::SSLClientSocketPool>& pool =
        session->ssl_socket_pool();

    handle_.Init(group_name, ssl_params, priority, this, pool,
                 net::BoundNetLog());
    return;
  }

  const scoped_refptr<net::TCPClientSocketPool>& pool =
      session->tcp_socket_pool();
  handle_.Init(group_name, tcp_params, priority, this, pool,
               net::BoundNetLog());
}

void Preconnect::RunWithParams(const Tuple1<int>& params) {
  if (params.a < 0 && handle_.socket())
    handle_.socket()->Disconnect();
  Release();
}
}  // chrome_browser_net
<commit_msg>(repair leak) Protect instance after commiting to use network<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/net/preconnect.h"

#include "base/histogram.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "net/base/host_port_pair.h"
#include "net/http/http_network_session.h"
#include "net/http/http_transaction_factory.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h"

namespace chrome_browser_net {

// static
bool Preconnect::preconnect_despite_proxy_ = false;

Preconnect::~Preconnect() {
  if (!handle_.is_initialized())
    return;
  DCHECK(motivation_ == UrlInfo::LEARNED_REFERAL_MOTIVATED ||
         motivation_ == UrlInfo::OMNIBOX_MOTIVATED);
  if (motivation_ == UrlInfo::OMNIBOX_MOTIVATED)
    handle_.socket()->SetOmniboxSpeculation();
  else
    handle_.socket()->SetSubresourceSpeculation();
  handle_.Reset();
}

// static
void Preconnect::PreconnectOnUIThread(const GURL& url,
    UrlInfo::ResolutionMotivation motivation) {
  // Prewarm connection to Search URL.
  ChromeThread::PostTask(
      ChromeThread::IO,
      FROM_HERE,
      NewRunnableFunction(Preconnect::PreconnectOnIOThread, url, motivation));
  return;
}

enum ProxyStatus {
  PROXY_STATUS_IGNORED,
  PROXY_UNINITIALIZED,
  PROXY_NOT_USED,
  PROXY_PAC_RESOLVER,
  PROXY_HAS_RULES,
  PROXY_MAX,
};

static void HistogramPreconnectStatus(ProxyStatus status) {
  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectProxyStatus", status, PROXY_MAX);
}

// static
void Preconnect::PreconnectOnIOThread(const GURL& url,
    UrlInfo::ResolutionMotivation motivation) {
  scoped_refptr<Preconnect> preconnect = new Preconnect(motivation);
  // TODO(jar): Should I use PostTask for LearnedSubresources to delay the
  // preconnection a tad?
  preconnect->Connect(url);
}

void Preconnect::Connect(const GURL& url) {
  URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
  if (!getter)
    return;
  if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
    LOG(DFATAL) << "This must be run only on the IO thread.";
    return;
  }

  URLRequestContext* context = getter->GetURLRequestContext();

  if (preconnect_despite_proxy_) {
    HistogramPreconnectStatus(PROXY_STATUS_IGNORED);
  } else {
    // Currently we avoid all preconnects if there is a proxy configuration.
    net::ProxyService* proxy_service = context->proxy_service();
    if (!proxy_service->config_has_been_initialized()) {
      HistogramPreconnectStatus(PROXY_UNINITIALIZED);
    } else {
      if (proxy_service->config().MayRequirePACResolver()) {
        HistogramPreconnectStatus(PROXY_PAC_RESOLVER);
        return;
      }
      if (!proxy_service->config().proxy_rules().empty()) {
        HistogramPreconnectStatus(PROXY_HAS_RULES);
        return;
      }
      HistogramPreconnectStatus(PROXY_NOT_USED);
    }
  }

  // We are now commited to doing the async preconnection call.
  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation_,
                            UrlInfo::MAX_MOTIVATED);
  AddRef();  // Stay alive until socket is available.

  net::HttpTransactionFactory* factory = context->http_transaction_factory();
  net::HttpNetworkSession* session = factory->GetSession();

  scoped_refptr<net::TCPSocketParams> tcp_params =
      new net::TCPSocketParams(url.host(), url.EffectiveIntPort(), net::LOW,
                               GURL(), false);

  net::HostPortPair endpoint(url.host(), url.EffectiveIntPort());
  std::string group_name = endpoint.ToString();

  // It almost doesn't matter whether we use net::LOWEST or net::HIGHEST
  // priority here, as we won't make a request, and will surrender the created
  // socket to the pool as soon as we can.  However, we would like to mark the
  // speculative socket as such, and IF we use a net::LOWEST priority, and if
  // a navigation asked for a socket (after us) then it would get our socket,
  // and we'd get its later-arriving socket, which might make us record that
  // the speculation didn't help :-/.  By using net::HIGHEST, we ensure that
  // a socket is given to us if "we asked first" and this allows us to mark it
  // as speculative, and better detect stats (if it gets used).
  // TODO(jar): histogram to see how often we accidentally use a previously-
  // unused socket, when a previously used socket was available.
  net::RequestPriority priority = net::HIGHEST;

  if (url.SchemeIs("https")) {
    group_name = StringPrintf("ssl/%s", group_name.c_str());

    net::SSLConfig ssl_config;
    session->ssl_config_service()->GetSSLConfig(&ssl_config);
    // All preconnects should be for main pages.
    ssl_config.verify_ev_cert = true;

    scoped_refptr<net::SSLSocketParams> ssl_params =
        new net::SSLSocketParams(tcp_params, NULL, NULL,
                                 net::ProxyServer::SCHEME_DIRECT,
                                 url.HostNoBrackets(), ssl_config,
                                 0, false, false);

    const scoped_refptr<net::SSLClientSocketPool>& pool =
        session->ssl_socket_pool();

    handle_.Init(group_name, ssl_params, priority, this, pool,
                 net::BoundNetLog());
    return;
  }

  const scoped_refptr<net::TCPClientSocketPool>& pool =
      session->tcp_socket_pool();
  handle_.Init(group_name, tcp_params, priority, this, pool,
               net::BoundNetLog());
}

void Preconnect::RunWithParams(const Tuple1<int>& params) {
  if (params.a < 0 && handle_.socket())
    handle_.socket()->Disconnect();
  Release();
}
}  // chrome_browser_net
<|endoftext|>


<commit_before><commit_msg>Use scoped_refptr for refcounted param in PluginService.<commit_after><|endoftext|>


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

#include "chrome/browser/plugin_updater.h"

#include <string>

#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_service.h"
#include "webkit/plugins/npapi/plugin_list.h"
#include "webkit/plugins/npapi/webplugininfo.h"

// How long to wait to save the plugin enabled information, which might need to
// go to disk.
#define kPluginUpdateDelayMs (60 * 1000)

PluginUpdater::PluginUpdater()
    : notify_pending_(false) {
}

DictionaryValue* PluginUpdater::CreatePluginFileSummary(
    const webkit::npapi::WebPluginInfo& plugin) {
  DictionaryValue* data = new DictionaryValue();
  data->SetString("path", plugin.path.value());
  data->SetString("name", plugin.name);
  data->SetString("version", plugin.version);
  data->SetBoolean("enabled", webkit::npapi::IsPluginEnabled(plugin));
  return data;
}

// static
ListValue* PluginUpdater::GetPluginGroupsData() {
  std::vector<webkit::npapi::PluginGroup> plugin_groups;
  webkit::npapi::PluginList::Singleton()->GetPluginGroups(true, &plugin_groups);

  // Construct DictionaryValues to return to the UI
  ListValue* plugin_groups_data = new ListValue();
  for (size_t i = 0; i < plugin_groups.size(); ++i) {
    plugin_groups_data->Append(plugin_groups[i].GetDataForUI());
  }
  return plugin_groups_data;
}

void PluginUpdater::EnablePluginGroup(bool enable, const string16& group_name) {
  webkit::npapi::PluginList::Singleton()->EnableGroup(enable, group_name);
  NotifyPluginStatusChanged();
}

void PluginUpdater::EnablePlugin(bool enable,
                                 const FilePath::StringType& path) {
  FilePath file_path(path);
  if (enable)
    webkit::npapi::PluginList::Singleton()->EnablePlugin(file_path);
  else
    webkit::npapi::PluginList::Singleton()->DisablePlugin(file_path);

  NotifyPluginStatusChanged();
}

void PluginUpdater::Observe(NotificationType type,
                            const NotificationSource& source,
                            const NotificationDetails& details) {
  DCHECK_EQ(NotificationType::PREF_CHANGED, type.value);
  const std::string* pref_name = Details<std::string>(details).ptr();
  if (!pref_name) {
    NOTREACHED();
    return;
  }
  if (*pref_name == prefs::kPluginsDisabledPlugins ||
      *pref_name == prefs::kPluginsDisabledPluginsExceptions ||
      *pref_name == prefs::kPluginsEnabledPlugins) {
    PrefService* pref_service = Source<PrefService>(source).ptr();
    const ListValue* disabled_list =
        pref_service->GetList(prefs::kPluginsDisabledPlugins);
    const ListValue* exceptions_list =
        pref_service->GetList(prefs::kPluginsDisabledPluginsExceptions);
    const ListValue* enabled_list =
        pref_service->GetList(prefs::kPluginsEnabledPlugins);
    UpdatePluginsStateFromPolicy(disabled_list, exceptions_list, enabled_list);
  }
}

void PluginUpdater::UpdatePluginsStateFromPolicy(
    const ListValue* disabled_list,
    const ListValue* exceptions_list,
    const ListValue* enabled_list) {
  std::set<string16> disabled_plugin_patterns;
  std::set<string16> disabled_plugin_exception_patterns;
  std::set<string16> enabled_plugin_patterns;

  ListValueToStringSet(disabled_list, &disabled_plugin_patterns);
  ListValueToStringSet(exceptions_list, &disabled_plugin_exception_patterns);
  ListValueToStringSet(enabled_list, &enabled_plugin_patterns);

  webkit::npapi::PluginGroup::SetPolicyEnforcedPluginPatterns(
      disabled_plugin_patterns,
      disabled_plugin_exception_patterns,
      enabled_plugin_patterns);

  NotifyPluginStatusChanged();
}

void PluginUpdater::ListValueToStringSet(const ListValue* src,
                                         std::set<string16>* dest) {
  DCHECK(src);
  DCHECK(dest);
  ListValue::const_iterator end(src->end());
  for (ListValue::const_iterator current(src->begin());
       current != end; ++current) {
    string16 plugin_name;
    if ((*current)->GetAsString(&plugin_name)) {
      dest->insert(plugin_name);
    }
  }
}

void PluginUpdater::SetProfile(Profile* profile) {
  bool update_internal_dir = false;
  FilePath last_internal_dir =
  profile->GetPrefs()->GetFilePath(prefs::kPluginsLastInternalDirectory);
  FilePath cur_internal_dir;
  if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &cur_internal_dir) &&
      cur_internal_dir != last_internal_dir) {
    update_internal_dir = true;
    profile->GetPrefs()->SetFilePath(
        prefs::kPluginsLastInternalDirectory, cur_internal_dir);
  }

  bool force_enable_internal_pdf = false;
  bool internal_pdf_enabled = false;
  string16 pdf_group_name =
      ASCIIToUTF16(chrome::ChromeContentClient::kPDFPluginName);
  FilePath pdf_path;
  PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path);
  FilePath::StringType pdf_path_str = pdf_path.value();
  if (!profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF)) {
    // We switched to the internal pdf plugin being on by default, and so we
    // need to force it to be enabled.  We only want to do it this once though,
    // i.e. we don't want to enable it again if the user disables it afterwards.
    profile->GetPrefs()->SetBoolean(prefs::kPluginsEnabledInternalPDF, true);
    force_enable_internal_pdf = true;
  }

  {  // Scoped update of prefs::kPluginsPluginsList.
    ListPrefUpdate update(profile->GetPrefs(), prefs::kPluginsPluginsList);
    ListValue* saved_plugins_list = update.Get();
    if (saved_plugins_list && !saved_plugins_list->empty()) {
      for (ListValue::const_iterator it = saved_plugins_list->begin();
           it != saved_plugins_list->end();
           ++it) {
        if (!(*it)->IsType(Value::TYPE_DICTIONARY)) {
          LOG(WARNING) << "Invalid entry in " << prefs::kPluginsPluginsList;
          continue;  // Oops, don't know what to do with this item.
        }

        DictionaryValue* plugin = static_cast<DictionaryValue*>(*it);
        string16 group_name;
        bool enabled = true;
        plugin->GetBoolean("enabled", &enabled);

        FilePath::StringType path;
        // The plugin list constains all the plugin files in addition to the
        // plugin groups.
        if (plugin->GetString("path", &path)) {
          // Files have a path attribute, groups don't.
          FilePath plugin_path(path);
          if (update_internal_dir &&
              FilePath::CompareIgnoreCase(plugin_path.DirName().value(),
                  last_internal_dir.value()) == 0) {
            // If the internal plugin directory has changed and if the plugin
            // looks internal, update its path in the prefs.
            plugin_path = cur_internal_dir.Append(plugin_path.BaseName());
            path = plugin_path.value();
            plugin->SetString("path", path);
          }

          if (FilePath::CompareIgnoreCase(path, pdf_path_str) == 0) {
            if (!enabled && force_enable_internal_pdf) {
              enabled = true;
              plugin->SetBoolean("enabled", true);
            }

            internal_pdf_enabled = enabled;
          }

          if (!enabled)
            webkit::npapi::PluginList::Singleton()->DisablePlugin(plugin_path);
        } else if (!enabled && plugin->GetString("name", &group_name)) {
          // Don't disable this group if it's for the pdf plugin and we just
          // forced it on.
          if (force_enable_internal_pdf && pdf_group_name == group_name)
            continue;

          // Otherwise this is a list of groups.
          EnablePluginGroup(false, group_name);
        }
      }
    } else {
      // If the saved plugin list is empty, then the call to UpdatePreferences()
      // below failed in an earlier run, possibly because the user closed the
      // browser too quickly. Try to force enable the internal PDF plugin again.
      force_enable_internal_pdf = true;
    }
  }  // Scoped update of prefs::kPluginsPluginsList.

  // Build the set of policy enabled/disabled plugin patterns once and cache it.
  // Don't do this in the constructor, there's no profile available there.
  const ListValue* disabled_plugins =
      profile->GetPrefs()->GetList(prefs::kPluginsDisabledPlugins);
  const ListValue* disabled_exception_plugins =
      profile->GetPrefs()->GetList(prefs::kPluginsDisabledPluginsExceptions);
  const ListValue* enabled_plugins =
      profile->GetPrefs()->GetList(prefs::kPluginsEnabledPlugins);
  UpdatePluginsStateFromPolicy(disabled_plugins,
                               disabled_exception_plugins,
                               enabled_plugins);

  registrar_.RemoveAll();
  registrar_.Init(profile->GetPrefs());
  registrar_.Add(prefs::kPluginsDisabledPlugins, this);
  registrar_.Add(prefs::kPluginsDisabledPluginsExceptions, this);
  registrar_.Add(prefs::kPluginsEnabledPlugins, this);

  if (force_enable_internal_pdf || internal_pdf_enabled) {
    // See http://crbug.com/50105 for background.
    EnablePluginGroup(false, ASCIIToUTF16(
        webkit::npapi::PluginGroup::kAdobeReaderGroupName));
  }

  if (force_enable_internal_pdf) {
    // We want to save this, but doing so requires loading the list of plugins,
    // so do it after a minute as to not impact startup performance.  Note that
    // plugins are loaded after 30s by the metrics service.
    UpdatePreferences(profile, kPluginUpdateDelayMs);
  }
}

void PluginUpdater::Shutdown() {
  registrar_.RemoveAll();
}

void PluginUpdater::UpdatePreferences(Profile* profile, int delay_ms) {
  BrowserThread::PostDelayedTask(
    BrowserThread::FILE,
    FROM_HERE,
    NewRunnableFunction(
        &PluginUpdater::GetPreferencesDataOnFileThread, profile), delay_ms);
}

void PluginUpdater::GetPreferencesDataOnFileThread(void* profile) {
  std::vector<webkit::npapi::WebPluginInfo> plugins;
  webkit::npapi::PluginList::Singleton()->GetPlugins(false, &plugins);

  std::vector<webkit::npapi::PluginGroup> groups;
  webkit::npapi::PluginList::Singleton()->GetPluginGroups(false, &groups);

  BrowserThread::PostTask(
    BrowserThread::UI,
    FROM_HERE,
    NewRunnableFunction(&PluginUpdater::OnUpdatePreferences,
                        static_cast<Profile*>(profile),
                        plugins, groups));
}

void PluginUpdater::OnUpdatePreferences(
    Profile* profile,
    const std::vector<webkit::npapi::WebPluginInfo>& plugins,
    const std::vector<webkit::npapi::PluginGroup>& groups) {
  ListPrefUpdate update(profile->GetPrefs(), prefs::kPluginsPluginsList);
  ListValue* plugins_list = update.Get();
  plugins_list->Clear();

  FilePath internal_dir;
  if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir))
    profile->GetPrefs()->SetFilePath(prefs::kPluginsLastInternalDirectory,
                                     internal_dir);

  // Add the plugin files.
  for (size_t i = 0; i < plugins.size(); ++i) {
    DictionaryValue* summary = CreatePluginFileSummary(plugins[i]);
    // If the plugin is managed by policy, store the user preferred state
    // instead.
    if (plugins[i].enabled & webkit::npapi::WebPluginInfo::MANAGED_MASK) {
      bool user_enabled =
          (plugins[i].enabled & webkit::npapi::WebPluginInfo::USER_MASK) ==
              webkit::npapi::WebPluginInfo::USER_ENABLED;
      summary->SetBoolean("enabled", user_enabled);
    }
    bool enabled_val;
    summary->GetBoolean("enabled", &enabled_val);
    plugins_list->Append(summary);
  }

  // Add the groups as well.
  for (size_t i = 0; i < groups.size(); ++i) {
      DictionaryValue* summary = groups[i].GetSummary();
      // If the plugin is disabled only by policy don't store this state in the
      // user pref store.
      if (!groups[i].Enabled() &&
          webkit::npapi::PluginGroup::IsPluginNameDisabledByPolicy(
              groups[i].GetGroupName()))
        summary->SetBoolean("enabled", true);
      plugins_list->Append(summary);
  }
}

void PluginUpdater::NotifyPluginStatusChanged() {
  if (notify_pending_)
    return;
  notify_pending_ = true;
  MessageLoop::current()->PostTask(
      FROM_HERE,
      NewRunnableFunction(&PluginUpdater::OnNotifyPluginStatusChanged));
}

void PluginUpdater::OnNotifyPluginStatusChanged() {
  GetInstance()->notify_pending_ = false;
  NotificationService::current()->Notify(
      NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
      Source<PluginUpdater>(GetInstance()),
      NotificationService::NoDetails());
}

/*static*/
PluginUpdater* PluginUpdater::GetInstance() {
  return Singleton<PluginUpdater>::get();
}

/*static*/
void PluginUpdater::RegisterPrefs(PrefService* prefs) {
  FilePath internal_dir;
  PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir);
  prefs->RegisterFilePathPref(prefs::kPluginsLastInternalDirectory,
                              internal_dir,
                              PrefService::UNSYNCABLE_PREF);
  prefs->RegisterListPref(prefs::kPluginsDisabledPlugins,
                          PrefService::UNSYNCABLE_PREF);
  prefs->RegisterListPref(prefs::kPluginsDisabledPluginsExceptions,
                          PrefService::UNSYNCABLE_PREF);
  prefs->RegisterListPref(prefs::kPluginsEnabledPlugins,
                          PrefService::UNSYNCABLE_PREF);
}
<commit_msg>Coverity: Check return values in PluginUpdater.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/plugin_updater.h"

#include <string>

#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_service.h"
#include "webkit/plugins/npapi/plugin_list.h"
#include "webkit/plugins/npapi/webplugininfo.h"

// How long to wait to save the plugin enabled information, which might need to
// go to disk.
#define kPluginUpdateDelayMs (60 * 1000)

PluginUpdater::PluginUpdater()
    : notify_pending_(false) {
}

DictionaryValue* PluginUpdater::CreatePluginFileSummary(
    const webkit::npapi::WebPluginInfo& plugin) {
  DictionaryValue* data = new DictionaryValue();
  data->SetString("path", plugin.path.value());
  data->SetString("name", plugin.name);
  data->SetString("version", plugin.version);
  data->SetBoolean("enabled", webkit::npapi::IsPluginEnabled(plugin));
  return data;
}

// static
ListValue* PluginUpdater::GetPluginGroupsData() {
  std::vector<webkit::npapi::PluginGroup> plugin_groups;
  webkit::npapi::PluginList::Singleton()->GetPluginGroups(true, &plugin_groups);

  // Construct DictionaryValues to return to the UI
  ListValue* plugin_groups_data = new ListValue();
  for (size_t i = 0; i < plugin_groups.size(); ++i) {
    plugin_groups_data->Append(plugin_groups[i].GetDataForUI());
  }
  return plugin_groups_data;
}

void PluginUpdater::EnablePluginGroup(bool enable, const string16& group_name) {
  webkit::npapi::PluginList::Singleton()->EnableGroup(enable, group_name);
  NotifyPluginStatusChanged();
}

void PluginUpdater::EnablePlugin(bool enable,
                                 const FilePath::StringType& path) {
  FilePath file_path(path);
  if (enable)
    webkit::npapi::PluginList::Singleton()->EnablePlugin(file_path);
  else
    webkit::npapi::PluginList::Singleton()->DisablePlugin(file_path);

  NotifyPluginStatusChanged();
}

void PluginUpdater::Observe(NotificationType type,
                            const NotificationSource& source,
                            const NotificationDetails& details) {
  DCHECK_EQ(NotificationType::PREF_CHANGED, type.value);
  const std::string* pref_name = Details<std::string>(details).ptr();
  if (!pref_name) {
    NOTREACHED();
    return;
  }
  if (*pref_name == prefs::kPluginsDisabledPlugins ||
      *pref_name == prefs::kPluginsDisabledPluginsExceptions ||
      *pref_name == prefs::kPluginsEnabledPlugins) {
    PrefService* pref_service = Source<PrefService>(source).ptr();
    const ListValue* disabled_list =
        pref_service->GetList(prefs::kPluginsDisabledPlugins);
    const ListValue* exceptions_list =
        pref_service->GetList(prefs::kPluginsDisabledPluginsExceptions);
    const ListValue* enabled_list =
        pref_service->GetList(prefs::kPluginsEnabledPlugins);
    UpdatePluginsStateFromPolicy(disabled_list, exceptions_list, enabled_list);
  }
}

void PluginUpdater::UpdatePluginsStateFromPolicy(
    const ListValue* disabled_list,
    const ListValue* exceptions_list,
    const ListValue* enabled_list) {
  std::set<string16> disabled_plugin_patterns;
  std::set<string16> disabled_plugin_exception_patterns;
  std::set<string16> enabled_plugin_patterns;

  ListValueToStringSet(disabled_list, &disabled_plugin_patterns);
  ListValueToStringSet(exceptions_list, &disabled_plugin_exception_patterns);
  ListValueToStringSet(enabled_list, &enabled_plugin_patterns);

  webkit::npapi::PluginGroup::SetPolicyEnforcedPluginPatterns(
      disabled_plugin_patterns,
      disabled_plugin_exception_patterns,
      enabled_plugin_patterns);

  NotifyPluginStatusChanged();
}

void PluginUpdater::ListValueToStringSet(const ListValue* src,
                                         std::set<string16>* dest) {
  DCHECK(src);
  DCHECK(dest);
  ListValue::const_iterator end(src->end());
  for (ListValue::const_iterator current(src->begin());
       current != end; ++current) {
    string16 plugin_name;
    if ((*current)->GetAsString(&plugin_name)) {
      dest->insert(plugin_name);
    }
  }
}

void PluginUpdater::SetProfile(Profile* profile) {
  bool update_internal_dir = false;
  FilePath last_internal_dir =
  profile->GetPrefs()->GetFilePath(prefs::kPluginsLastInternalDirectory);
  FilePath cur_internal_dir;
  if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &cur_internal_dir) &&
      cur_internal_dir != last_internal_dir) {
    update_internal_dir = true;
    profile->GetPrefs()->SetFilePath(
        prefs::kPluginsLastInternalDirectory, cur_internal_dir);
  }

  bool force_enable_internal_pdf = false;
  bool internal_pdf_enabled = false;
  string16 pdf_group_name =
      ASCIIToUTF16(chrome::ChromeContentClient::kPDFPluginName);
  FilePath pdf_path;
  PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path);
  FilePath::StringType pdf_path_str = pdf_path.value();
  if (!profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF)) {
    // We switched to the internal pdf plugin being on by default, and so we
    // need to force it to be enabled.  We only want to do it this once though,
    // i.e. we don't want to enable it again if the user disables it afterwards.
    profile->GetPrefs()->SetBoolean(prefs::kPluginsEnabledInternalPDF, true);
    force_enable_internal_pdf = true;
  }

  {  // Scoped update of prefs::kPluginsPluginsList.
    ListPrefUpdate update(profile->GetPrefs(), prefs::kPluginsPluginsList);
    ListValue* saved_plugins_list = update.Get();
    if (saved_plugins_list && !saved_plugins_list->empty()) {
      for (ListValue::const_iterator it = saved_plugins_list->begin();
           it != saved_plugins_list->end();
           ++it) {
        if (!(*it)->IsType(Value::TYPE_DICTIONARY)) {
          LOG(WARNING) << "Invalid entry in " << prefs::kPluginsPluginsList;
          continue;  // Oops, don't know what to do with this item.
        }

        DictionaryValue* plugin = static_cast<DictionaryValue*>(*it);
        string16 group_name;
        bool enabled;
        if (!plugin->GetBoolean("enabled", &enabled))
          enabled = true;

        FilePath::StringType path;
        // The plugin list constains all the plugin files in addition to the
        // plugin groups.
        if (plugin->GetString("path", &path)) {
          // Files have a path attribute, groups don't.
          FilePath plugin_path(path);
          if (update_internal_dir &&
              FilePath::CompareIgnoreCase(plugin_path.DirName().value(),
                  last_internal_dir.value()) == 0) {
            // If the internal plugin directory has changed and if the plugin
            // looks internal, update its path in the prefs.
            plugin_path = cur_internal_dir.Append(plugin_path.BaseName());
            path = plugin_path.value();
            plugin->SetString("path", path);
          }

          if (FilePath::CompareIgnoreCase(path, pdf_path_str) == 0) {
            if (!enabled && force_enable_internal_pdf) {
              enabled = true;
              plugin->SetBoolean("enabled", true);
            }

            internal_pdf_enabled = enabled;
          }

          if (!enabled)
            webkit::npapi::PluginList::Singleton()->DisablePlugin(plugin_path);
        } else if (!enabled && plugin->GetString("name", &group_name)) {
          // Don't disable this group if it's for the pdf plugin and we just
          // forced it on.
          if (force_enable_internal_pdf && pdf_group_name == group_name)
            continue;

          // Otherwise this is a list of groups.
          EnablePluginGroup(false, group_name);
        }
      }
    } else {
      // If the saved plugin list is empty, then the call to UpdatePreferences()
      // below failed in an earlier run, possibly because the user closed the
      // browser too quickly. Try to force enable the internal PDF plugin again.
      force_enable_internal_pdf = true;
    }
  }  // Scoped update of prefs::kPluginsPluginsList.

  // Build the set of policy enabled/disabled plugin patterns once and cache it.
  // Don't do this in the constructor, there's no profile available there.
  const ListValue* disabled_plugins =
      profile->GetPrefs()->GetList(prefs::kPluginsDisabledPlugins);
  const ListValue* disabled_exception_plugins =
      profile->GetPrefs()->GetList(prefs::kPluginsDisabledPluginsExceptions);
  const ListValue* enabled_plugins =
      profile->GetPrefs()->GetList(prefs::kPluginsEnabledPlugins);
  UpdatePluginsStateFromPolicy(disabled_plugins,
                               disabled_exception_plugins,
                               enabled_plugins);

  registrar_.RemoveAll();
  registrar_.Init(profile->GetPrefs());
  registrar_.Add(prefs::kPluginsDisabledPlugins, this);
  registrar_.Add(prefs::kPluginsDisabledPluginsExceptions, this);
  registrar_.Add(prefs::kPluginsEnabledPlugins, this);

  if (force_enable_internal_pdf || internal_pdf_enabled) {
    // See http://crbug.com/50105 for background.
    EnablePluginGroup(false, ASCIIToUTF16(
        webkit::npapi::PluginGroup::kAdobeReaderGroupName));
  }

  if (force_enable_internal_pdf) {
    // We want to save this, but doing so requires loading the list of plugins,
    // so do it after a minute as to not impact startup performance.  Note that
    // plugins are loaded after 30s by the metrics service.
    UpdatePreferences(profile, kPluginUpdateDelayMs);
  }
}

void PluginUpdater::Shutdown() {
  registrar_.RemoveAll();
}

void PluginUpdater::UpdatePreferences(Profile* profile, int delay_ms) {
  BrowserThread::PostDelayedTask(
    BrowserThread::FILE,
    FROM_HERE,
    NewRunnableFunction(
        &PluginUpdater::GetPreferencesDataOnFileThread, profile), delay_ms);
}

void PluginUpdater::GetPreferencesDataOnFileThread(void* profile) {
  std::vector<webkit::npapi::WebPluginInfo> plugins;
  webkit::npapi::PluginList::Singleton()->GetPlugins(false, &plugins);

  std::vector<webkit::npapi::PluginGroup> groups;
  webkit::npapi::PluginList::Singleton()->GetPluginGroups(false, &groups);

  BrowserThread::PostTask(
    BrowserThread::UI,
    FROM_HERE,
    NewRunnableFunction(&PluginUpdater::OnUpdatePreferences,
                        static_cast<Profile*>(profile),
                        plugins, groups));
}

void PluginUpdater::OnUpdatePreferences(
    Profile* profile,
    const std::vector<webkit::npapi::WebPluginInfo>& plugins,
    const std::vector<webkit::npapi::PluginGroup>& groups) {
  ListPrefUpdate update(profile->GetPrefs(), prefs::kPluginsPluginsList);
  ListValue* plugins_list = update.Get();
  plugins_list->Clear();

  FilePath internal_dir;
  if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir))
    profile->GetPrefs()->SetFilePath(prefs::kPluginsLastInternalDirectory,
                                     internal_dir);

  // Add the plugin files.
  for (size_t i = 0; i < plugins.size(); ++i) {
    DictionaryValue* summary = CreatePluginFileSummary(plugins[i]);
    // If the plugin is managed by policy, store the user preferred state
    // instead.
    if (plugins[i].enabled & webkit::npapi::WebPluginInfo::MANAGED_MASK) {
      bool user_enabled =
          (plugins[i].enabled & webkit::npapi::WebPluginInfo::USER_MASK) ==
              webkit::npapi::WebPluginInfo::USER_ENABLED;
      summary->SetBoolean("enabled", user_enabled);
    }
    plugins_list->Append(summary);
  }

  // Add the groups as well.
  for (size_t i = 0; i < groups.size(); ++i) {
      DictionaryValue* summary = groups[i].GetSummary();
      // If the plugin is disabled only by policy don't store this state in the
      // user pref store.
      if (!groups[i].Enabled() &&
          webkit::npapi::PluginGroup::IsPluginNameDisabledByPolicy(
              groups[i].GetGroupName()))
        summary->SetBoolean("enabled", true);
      plugins_list->Append(summary);
  }
}

void PluginUpdater::NotifyPluginStatusChanged() {
  if (notify_pending_)
    return;
  notify_pending_ = true;
  MessageLoop::current()->PostTask(
      FROM_HERE,
      NewRunnableFunction(&PluginUpdater::OnNotifyPluginStatusChanged));
}

void PluginUpdater::OnNotifyPluginStatusChanged() {
  GetInstance()->notify_pending_ = false;
  NotificationService::current()->Notify(
      NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
      Source<PluginUpdater>(GetInstance()),
      NotificationService::NoDetails());
}

/*static*/
PluginUpdater* PluginUpdater::GetInstance() {
  return Singleton<PluginUpdater>::get();
}

/*static*/
void PluginUpdater::RegisterPrefs(PrefService* prefs) {
  FilePath internal_dir;
  PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir);
  prefs->RegisterFilePathPref(prefs::kPluginsLastInternalDirectory,
                              internal_dir,
                              PrefService::UNSYNCABLE_PREF);
  prefs->RegisterListPref(prefs::kPluginsDisabledPlugins,
                          PrefService::UNSYNCABLE_PREF);
  prefs->RegisterListPref(prefs::kPluginsDisabledPluginsExceptions,
                          PrefService::UNSYNCABLE_PREF);
  prefs->RegisterListPref(prefs::kPluginsEnabledPlugins,
                          PrefService::UNSYNCABLE_PREF);
}
<|endoftext|>


<commit_before><commit_msg>Update evicted dlls list<commit_after><|endoftext|>


<commit_before><commit_msg>Add more info to a dcheck to see why DuplicateHandle is failing on the buildbot.<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: breakiterator_unicode.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: khong $ $Date: 2002-04-16 00:05:32 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <breakiterator_unicode.hxx>
#include <unicode.hxx>
#include <unicode/locid.h>

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::rtl;

namespace com { namespace sun { namespace star { namespace i18n {

#define ERROR RuntimeException()
static UErrorCode status; // status is shared in all calls to Calendar, it has to be reset for each call.

#define LOAD_CHARACTER_BREAKITERATOR    0
#define LOAD_WORD_BREAKITERATOR     1
#define LOAD_SENTENCE_BREAKITERATOR 2
#define LOAD_LINE_BREAKITERATOR     3

#define ImplementName "com.sun.star.i18n.BreakIterator_Unicode";

BreakIterator_Unicode::BreakIterator_Unicode()
{
    characterBreak = wordBreak = sentenceBreak = lineBreak = NULL;
    cBreakIterator = ImplementName;
}

BreakIterator_Unicode::~BreakIterator_Unicode()
{
    if (characterBreak) delete characterBreak;
    if (wordBreak) delete wordBreak;
    if (sentenceBreak) delete sentenceBreak;
    if (lineBreak) delete lineBreak;
}

// loading ICU breakiterator on demand.
static icu::BreakIterator* SAL_CALL loadICUBreakIterator(const com::sun::star::lang::Locale& rLocale, sal_Int16 which) throw(RuntimeException)
{
    icu::BreakIterator *breakiterator = NULL;
    icu::Locale icuLocale(
        OUStringToOString(rLocale.Language, RTL_TEXTENCODING_ASCII_US).getStr(),
        OUStringToOString(rLocale.Country, RTL_TEXTENCODING_ASCII_US).getStr(),
        OUStringToOString(rLocale.Variant, RTL_TEXTENCODING_ASCII_US).getStr());

    status = U_ZERO_ERROR;
    switch (which) {
        case LOAD_CHARACTER_BREAKITERATOR:
        breakiterator =  icu::BreakIterator::createCharacterInstance(icuLocale, status);
        break;
        case LOAD_WORD_BREAKITERATOR:
        breakiterator = icu::BreakIterator::createWordInstance(icuLocale, status);
        break;
        case LOAD_SENTENCE_BREAKITERATOR:
        breakiterator = icu::BreakIterator::createSentenceInstance(icuLocale, status);
        break;
        case LOAD_LINE_BREAKITERATOR:
        breakiterator = icu::BreakIterator::createLineInstance(icuLocale, status);
        break;
    }
    if ( !U_SUCCESS(status) ) throw ERROR;

    return breakiterator;
}

sal_Int32 SAL_CALL BreakIterator_Unicode::nextCharacters( const OUString& Text,
    sal_Int32 nStartPos, const lang::Locale &rLocale,
    sal_Int16 nCharacterIteratorMode, sal_Int32 nCount, sal_Int32& nDone )
    throw(RuntimeException)
{
    if (!characterBreak) characterBreak = loadICUBreakIterator(rLocale, LOAD_CHARACTER_BREAKITERATOR);

    characterBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));
    for (nDone = 0; nDone < nCount; nDone++) {
        nStartPos = characterBreak->following(nStartPos);
        if (nStartPos == BreakIterator::DONE)
        return Text.getLength();
    }
    return nStartPos;
}

sal_Int32 SAL_CALL BreakIterator_Unicode::previousCharacters( const OUString& Text,
    sal_Int32 nStartPos, const lang::Locale& rLocale,
    sal_Int16 nCharacterIteratorMode, sal_Int32 nCount, sal_Int32& nDone )
    throw(RuntimeException)
{
    if (!characterBreak) characterBreak = loadICUBreakIterator(rLocale, LOAD_CHARACTER_BREAKITERATOR);

    characterBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));
    for (nDone = 0; nDone < nCount; nDone++) {
        nStartPos = characterBreak->preceding(nStartPos);
        if (nStartPos == BreakIterator::DONE)
        return 0;
    }
    return nStartPos;
}

Boundary SAL_CALL BreakIterator_Unicode::nextWord( const OUString& Text, sal_Int32 nStartPos,
    const lang::Locale& rLocale, sal_Int16 rWordType ) throw(RuntimeException)
{
    if (!wordBreak) wordBreak = loadICUBreakIterator(rLocale, LOAD_WORD_BREAKITERATOR);

    wordBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));

    result.startPos = wordBreak->following(nStartPos);
    if( result.startPos >= Text.getLength() || result.startPos == BreakIterator::DONE )
        result.endPos = result.startPos;
    else {
        if ( (rWordType == WordType::ANYWORD_IGNOREWHITESPACES ||
            rWordType == WordType::DICTIONARY_WORD ) &&
            unicode::isWhiteSpace(Text[result.startPos]) )
        result.startPos = wordBreak->following(result.startPos);

        result.endPos = wordBreak->following(result.startPos);
        if(result.endPos == BreakIterator::DONE)
        result.endPos = result.startPos;
    }
    return result;
}

Boundary SAL_CALL BreakIterator_Unicode::previousWord(const OUString& Text, sal_Int32 nStartPos,
    const lang::Locale& rLocale, sal_Int16 rWordType) throw(RuntimeException)
{
    if (!wordBreak) wordBreak = loadICUBreakIterator(rLocale, LOAD_WORD_BREAKITERATOR);

    wordBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));

    result.startPos = wordBreak->preceding(nStartPos);
    if( result.startPos < 0 || result.startPos == BreakIterator::DONE)
        result.endPos = result.startPos;
    else {
        if ( (rWordType == WordType::ANYWORD_IGNOREWHITESPACES ||
            rWordType == WordType::DICTIONARY_WORD) &&
            unicode::isWhiteSpace(Text[result.startPos]) )
        result.startPos = wordBreak->preceding(result.startPos);

        result.endPos = wordBreak->following(result.startPos);
        if(result.endPos == BreakIterator::DONE)
        result.endPos = result.startPos;
    }
    return result;
}

Boundary SAL_CALL BreakIterator_Unicode::getWordBoundary( const OUString& Text, sal_Int32 nPos, const lang::Locale& rLocale,
    sal_Int16 rWordType, sal_Bool bDirection ) throw(RuntimeException)
{
    if (!wordBreak) wordBreak = loadICUBreakIterator(rLocale, LOAD_WORD_BREAKITERATOR);

    sal_Int32 len = Text.getLength();
    wordBreak->setText(UnicodeString(Text.getStr(), len));

    if(wordBreak->isBoundary(nPos)) {
        result.startPos = result.endPos = nPos;
        if((bDirection || nPos == 0) && nPos < len) //forward
        result.endPos = wordBreak->following(nPos);
        else
        result.startPos = wordBreak->preceding(nPos);
    } else {
        if(nPos <= 0) {
        result.startPos = 0;
        result.endPos = len ? wordBreak->following((sal_Int32)0) : 0;
        } else if(nPos >= len) {
        result.startPos = wordBreak->preceding(len);
        result.endPos = len;
        } else {
        result.startPos = wordBreak->preceding(nPos);
        result.endPos = wordBreak->following(nPos);
        }
    }
    if (result.startPos == BreakIterator::DONE)
        result.startPos = result.endPos;
    else if (result.endPos == BreakIterator::DONE)
        result.endPos = result.startPos;

    return result;
}

sal_Int32 SAL_CALL BreakIterator_Unicode::beginOfSentence( const OUString& Text, sal_Int32 nStartPos,
    const lang::Locale &rLocale ) throw(RuntimeException)
{
    if (!sentenceBreak) sentenceBreak = loadICUBreakIterator(rLocale, LOAD_SENTENCE_BREAKITERATOR);

    sentenceBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));
    return sentenceBreak->preceding(nStartPos);
}

sal_Int32 SAL_CALL BreakIterator_Unicode::endOfSentence( const OUString& Text, sal_Int32 nStartPos,
    const lang::Locale &rLocale ) throw(RuntimeException)
{
    if (!sentenceBreak) sentenceBreak = loadICUBreakIterator(rLocale, LOAD_SENTENCE_BREAKITERATOR);

    sentenceBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));

    sal_Int32 nPos = sentenceBreak->following(nStartPos);

        while (--nPos >= 0 && unicode::isWhiteSpace(Text[nPos]));

        return ++nPos;
}

LineBreakResults SAL_CALL BreakIterator_Unicode::getLineBreak(
    const OUString& Text, sal_Int32 nStartPos,
    const lang::Locale& rLocale, sal_Int32 nMinBreakPos,
    const LineBreakHyphenationOptions& hOptions,
    const LineBreakUserOptions& bOptions ) throw(RuntimeException)
{
    LineBreakResults result;

    if (!lineBreak) lineBreak = loadICUBreakIterator(rLocale, LOAD_LINE_BREAKITERATOR);

    if (bOptions.allowPunctuationOutsideMargin &&
        bOptions.forbiddenBeginCharacters.indexOf(Text[nStartPos]) != -1 &&
        ++nStartPos == Text.getLength()) {
        result.breakIndex = nStartPos;
        result.breakType = BreakType::WORDBOUNDARY;
        return result;
    }

    lineBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));

    if (lineBreak->isBoundary(nStartPos)) { //Line boundary break
        result.breakIndex = nStartPos;
        result.breakType = BreakType::WORDBOUNDARY;
    } else if (hOptions.rHyphenator.is()) { //Hyphenation break
        Boundary wBoundary = getWordBoundary( Text, nStartPos, rLocale,
                        WordType::ANYWORD_IGNOREWHITESPACES, false);
        Reference< linguistic2::XHyphenatedWord > aHyphenatedWord;
        aHyphenatedWord = hOptions.rHyphenator->hyphenate(Text.copy(wBoundary.startPos,
        wBoundary.endPos - wBoundary.startPos), rLocale,
        hOptions.hyphenIndex - wBoundary.startPos, hOptions.aHyphenationOptions);
        if (aHyphenatedWord.is()) {
        result.rHyphenatedWord = aHyphenatedWord;
        if(wBoundary.startPos + aHyphenatedWord->getHyphenationPos() + 1 < nMinBreakPos )
            result.breakIndex = -1;
        else
            result.breakIndex = wBoundary.startPos; //aHyphenatedWord->getHyphenationPos();
        result.breakType = BreakType::HYPHENATION;
        } else {
        result.breakIndex = lineBreak->preceding(nStartPos);
        result.breakType = BreakType::WORDBOUNDARY;;
        }
    } else { //word boundary break
        result.breakIndex = lineBreak->preceding(nStartPos);
        result.breakType = BreakType::WORDBOUNDARY;
    }

    if (0 < result.breakIndex && result.breakIndex < Text.getLength() && bOptions.applyForbiddenRules) {
        while (result.breakIndex > 0 &&
            (bOptions.forbiddenBeginCharacters.indexOf(Text[result.breakIndex]) != -1 ||
            bOptions.forbiddenEndCharacters.indexOf(Text[result.breakIndex - 1]) != -1))
        result.breakIndex--;
    }
    return result;
}

OUString SAL_CALL
BreakIterator_Unicode::getImplementationName(void) throw( RuntimeException )
{
    return OUString::createFromAscii(cBreakIterator);
}

sal_Bool SAL_CALL
BreakIterator_Unicode::supportsService(const OUString& rServiceName) throw( RuntimeException )
{
    return !rServiceName.compareToAscii(cBreakIterator);
}

Sequence< OUString > SAL_CALL
BreakIterator_Unicode::getSupportedServiceNames(void) throw( RuntimeException )
{
    Sequence< OUString > aRet(1);
    aRet[0] = OUString::createFromAscii(cBreakIterator);
    return aRet;
}

} } } }
<commit_msg>#96776#Wrong line break behind custom quote \u00BB and colon ':', #99249# Regression: Line break for Korean (Hangul) characters is incorrect<commit_after>/*************************************************************************
 *
 *  $RCSfile: breakiterator_unicode.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: khong $ $Date: 2002-05-14 17:42:05 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <breakiterator_unicode.hxx>
#include <unicode.hxx>
#include <unicode/locid.h>

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::rtl;

namespace com { namespace sun { namespace star { namespace i18n {

#define ERROR RuntimeException()
static UErrorCode status; // status is shared in all calls to Calendar, it has to be reset for each call.

#define LOAD_CHARACTER_BREAKITERATOR    0
#define LOAD_WORD_BREAKITERATOR     1
#define LOAD_SENTENCE_BREAKITERATOR 2
#define LOAD_LINE_BREAKITERATOR     3

#define ImplementName "com.sun.star.i18n.BreakIterator_Unicode";

BreakIterator_Unicode::BreakIterator_Unicode()
{
    characterBreak = wordBreak = sentenceBreak = lineBreak = NULL;
    cBreakIterator = ImplementName;
}

BreakIterator_Unicode::~BreakIterator_Unicode()
{
    if (characterBreak) delete characterBreak;
    if (wordBreak) delete wordBreak;
    if (sentenceBreak) delete sentenceBreak;
    if (lineBreak) delete lineBreak;
}

// loading ICU breakiterator on demand.
static icu::BreakIterator* SAL_CALL loadICUBreakIterator(const com::sun::star::lang::Locale& rLocale, sal_Int16 which) throw(RuntimeException)
{
    icu::BreakIterator *breakiterator = NULL;
    icu::Locale icuLocale(
        OUStringToOString(rLocale.Language, RTL_TEXTENCODING_ASCII_US).getStr(),
        OUStringToOString(rLocale.Country, RTL_TEXTENCODING_ASCII_US).getStr(),
        OUStringToOString(rLocale.Variant, RTL_TEXTENCODING_ASCII_US).getStr());

    status = U_ZERO_ERROR;
    switch (which) {
        case LOAD_CHARACTER_BREAKITERATOR:
        breakiterator =  icu::BreakIterator::createCharacterInstance(icuLocale, status);
        break;
        case LOAD_WORD_BREAKITERATOR:
        breakiterator = icu::BreakIterator::createWordInstance(icuLocale, status);
        break;
        case LOAD_SENTENCE_BREAKITERATOR:
        breakiterator = icu::BreakIterator::createSentenceInstance(icuLocale, status);
        break;
        case LOAD_LINE_BREAKITERATOR:
        breakiterator = icu::BreakIterator::createLineInstance(icuLocale, status);
        break;
    }
    if ( !U_SUCCESS(status) ) throw ERROR;

    return breakiterator;
}

sal_Int32 SAL_CALL BreakIterator_Unicode::nextCharacters( const OUString& Text,
    sal_Int32 nStartPos, const lang::Locale &rLocale,
    sal_Int16 nCharacterIteratorMode, sal_Int32 nCount, sal_Int32& nDone )
    throw(RuntimeException)
{
    if (!characterBreak) characterBreak = loadICUBreakIterator(rLocale, LOAD_CHARACTER_BREAKITERATOR);

    characterBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));
    for (nDone = 0; nDone < nCount; nDone++) {
        nStartPos = characterBreak->following(nStartPos);
        if (nStartPos == BreakIterator::DONE)
        return Text.getLength();
    }
    return nStartPos;
}

sal_Int32 SAL_CALL BreakIterator_Unicode::previousCharacters( const OUString& Text,
    sal_Int32 nStartPos, const lang::Locale& rLocale,
    sal_Int16 nCharacterIteratorMode, sal_Int32 nCount, sal_Int32& nDone )
    throw(RuntimeException)
{
    if (!characterBreak) characterBreak = loadICUBreakIterator(rLocale, LOAD_CHARACTER_BREAKITERATOR);

    characterBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));
    for (nDone = 0; nDone < nCount; nDone++) {
        nStartPos = characterBreak->preceding(nStartPos);
        if (nStartPos == BreakIterator::DONE)
        return 0;
    }
    return nStartPos;
}

Boundary SAL_CALL BreakIterator_Unicode::nextWord( const OUString& Text, sal_Int32 nStartPos,
    const lang::Locale& rLocale, sal_Int16 rWordType ) throw(RuntimeException)
{
    if (!wordBreak) wordBreak = loadICUBreakIterator(rLocale, LOAD_WORD_BREAKITERATOR);

    wordBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));

    result.startPos = wordBreak->following(nStartPos);
    if( result.startPos >= Text.getLength() || result.startPos == BreakIterator::DONE )
        result.endPos = result.startPos;
    else {
        if ( (rWordType == WordType::ANYWORD_IGNOREWHITESPACES ||
            rWordType == WordType::DICTIONARY_WORD ) &&
            unicode::isWhiteSpace(Text[result.startPos]) )
        result.startPos = wordBreak->following(result.startPos);

        result.endPos = wordBreak->following(result.startPos);
        if(result.endPos == BreakIterator::DONE)
        result.endPos = result.startPos;
    }
    return result;
}

Boundary SAL_CALL BreakIterator_Unicode::previousWord(const OUString& Text, sal_Int32 nStartPos,
    const lang::Locale& rLocale, sal_Int16 rWordType) throw(RuntimeException)
{
    if (!wordBreak) wordBreak = loadICUBreakIterator(rLocale, LOAD_WORD_BREAKITERATOR);

    wordBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));

    result.startPos = wordBreak->preceding(nStartPos);
    if( result.startPos < 0 || result.startPos == BreakIterator::DONE)
        result.endPos = result.startPos;
    else {
        if ( (rWordType == WordType::ANYWORD_IGNOREWHITESPACES ||
            rWordType == WordType::DICTIONARY_WORD) &&
            unicode::isWhiteSpace(Text[result.startPos]) )
        result.startPos = wordBreak->preceding(result.startPos);

        result.endPos = wordBreak->following(result.startPos);
        if(result.endPos == BreakIterator::DONE)
        result.endPos = result.startPos;
    }
    return result;
}

Boundary SAL_CALL BreakIterator_Unicode::getWordBoundary( const OUString& Text, sal_Int32 nPos, const lang::Locale& rLocale,
    sal_Int16 rWordType, sal_Bool bDirection ) throw(RuntimeException)
{
    if (!wordBreak) wordBreak = loadICUBreakIterator(rLocale, LOAD_WORD_BREAKITERATOR);

    sal_Int32 len = Text.getLength();
    wordBreak->setText(UnicodeString(Text.getStr(), len));

    if(wordBreak->isBoundary(nPos)) {
        result.startPos = result.endPos = nPos;
        if((bDirection || nPos == 0) && nPos < len) //forward
        result.endPos = wordBreak->following(nPos);
        else
        result.startPos = wordBreak->preceding(nPos);
    } else {
        if(nPos <= 0) {
        result.startPos = 0;
        result.endPos = len ? wordBreak->following((sal_Int32)0) : 0;
        } else if(nPos >= len) {
        result.startPos = wordBreak->preceding(len);
        result.endPos = len;
        } else {
        result.startPos = wordBreak->preceding(nPos);
        result.endPos = wordBreak->following(nPos);
        }
    }
    if (result.startPos == BreakIterator::DONE)
        result.startPos = result.endPos;
    else if (result.endPos == BreakIterator::DONE)
        result.endPos = result.startPos;

    return result;
}

sal_Int32 SAL_CALL BreakIterator_Unicode::beginOfSentence( const OUString& Text, sal_Int32 nStartPos,
    const lang::Locale &rLocale ) throw(RuntimeException)
{
    if (!sentenceBreak) sentenceBreak = loadICUBreakIterator(rLocale, LOAD_SENTENCE_BREAKITERATOR);

    sentenceBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));
    return sentenceBreak->preceding(nStartPos);
}

sal_Int32 SAL_CALL BreakIterator_Unicode::endOfSentence( const OUString& Text, sal_Int32 nStartPos,
    const lang::Locale &rLocale ) throw(RuntimeException)
{
    if (!sentenceBreak) sentenceBreak = loadICUBreakIterator(rLocale, LOAD_SENTENCE_BREAKITERATOR);

    sentenceBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));

    sal_Int32 nPos = sentenceBreak->following(nStartPos);

        while (--nPos >= 0 && unicode::isWhiteSpace(Text[nPos]));

        return ++nPos;
}

LineBreakResults SAL_CALL BreakIterator_Unicode::getLineBreak(
    const OUString& Text, sal_Int32 nStartPos,
    const lang::Locale& rLocale, sal_Int32 nMinBreakPos,
    const LineBreakHyphenationOptions& hOptions,
    const LineBreakUserOptions& bOptions ) throw(RuntimeException)
{
    LineBreakResults result;

    if (!lineBreak) lineBreak = loadICUBreakIterator(rLocale, LOAD_LINE_BREAKITERATOR);

    if ((bOptions.allowPunctuationOutsideMargin &&
        bOptions.forbiddenBeginCharacters.indexOf(Text[nStartPos]) != -1 &&
        ++nStartPos == Text.getLength()) ||
        // Bug 4503876. We fixed the problem in 6.0 by changing line break data.
        // Since we are using ICU data after 6.0, and it is difficult to patch line
        // break data in ICU, because the data is in binary mode, we have to add
        // following condition to break Hangul characters for line break.
        unicode::isUnicodeScriptType(Text[nStartPos], UnicodeScript_kHangulSyllable)) {
        result.breakIndex = nStartPos;
        result.breakType = BreakType::WORDBOUNDARY;
        return result;
    }

    lineBreak->setText(UnicodeString(Text.getStr(), Text.getLength()));

    if (lineBreak->isBoundary(nStartPos)) { //Line boundary break
        result.breakIndex = nStartPos;
        result.breakType = BreakType::WORDBOUNDARY;
    } else if (hOptions.rHyphenator.is()) { //Hyphenation break
        Boundary wBoundary = getWordBoundary( Text, nStartPos, rLocale,
                        WordType::ANYWORD_IGNOREWHITESPACES, false);
        Reference< linguistic2::XHyphenatedWord > aHyphenatedWord;
        aHyphenatedWord = hOptions.rHyphenator->hyphenate(Text.copy(wBoundary.startPos,
        wBoundary.endPos - wBoundary.startPos), rLocale,
        hOptions.hyphenIndex - wBoundary.startPos, hOptions.aHyphenationOptions);
        if (aHyphenatedWord.is()) {
        result.rHyphenatedWord = aHyphenatedWord;
        if(wBoundary.startPos + aHyphenatedWord->getHyphenationPos() + 1 < nMinBreakPos )
            result.breakIndex = -1;
        else
            result.breakIndex = wBoundary.startPos; //aHyphenatedWord->getHyphenationPos();
        result.breakType = BreakType::HYPHENATION;
        } else {
        result.breakIndex = lineBreak->preceding(nStartPos);
        result.breakType = BreakType::WORDBOUNDARY;;
        }
    } else { //word boundary break
        result.breakIndex = lineBreak->preceding(nStartPos);
        result.breakType = BreakType::WORDBOUNDARY;
    }

    if (0 < result.breakIndex && result.breakIndex < Text.getLength()) {

        // Bug 4627181. ICU has defined line can be broken after ':' and 0x00BB (end quotation mark).
        // In StarOffice, we don't want ':' to be broken in any locale and 0x00BB in German locale
        // since 0x00BB are commonly used as start quotation mark in German.
        sal_Unicode ch = Text[result.breakIndex-1];
        while (ch == 0x003A || (ch == 0x00BB && rLocale.Language.compareToAscii("de") == 0)) {
        result.breakIndex = lineBreak->preceding(result.breakIndex-1);
        if (result.breakIndex <= 0) return result;
        ch = Text[result.breakIndex-1];
        }

        if (bOptions.applyForbiddenRules) {
        while (result.breakIndex > 0 &&
            (bOptions.forbiddenBeginCharacters.indexOf(Text[result.breakIndex]) != -1 ||
            bOptions.forbiddenEndCharacters.indexOf(Text[result.breakIndex - 1]) != -1))
            result.breakIndex--;
        }
    }
    return result;
}

OUString SAL_CALL
BreakIterator_Unicode::getImplementationName(void) throw( RuntimeException )
{
    return OUString::createFromAscii(cBreakIterator);
}

sal_Bool SAL_CALL
BreakIterator_Unicode::supportsService(const OUString& rServiceName) throw( RuntimeException )
{
    return !rServiceName.compareToAscii(cBreakIterator);
}

Sequence< OUString > SAL_CALL
BreakIterator_Unicode::getSupportedServiceNames(void) throw( RuntimeException )
{
    Sequence< OUString > aRet(1);
    aRet[0] = OUString::createFromAscii(cBreakIterator);
    return aRet;
}

} } } }
<|endoftext|>