<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osg/CullSettings>

using namespace osg;

void CullSettings::setDefaults()
{
    _cullingMode = DEFAULT_CULLING;
    _LODScale = 1.0f;
    _smallFeatureCullingPixelSize = 2.0f;

    _computeNearFar = COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES;
    _nearFarRatio = 0.0005f;
    _impostorActive = true;
    _depthSortImpostorSprites = false;
    _impostorPixelErrorThreshold = 4.0f;
    _numFramesToKeepImpostorSprites = 10;
    _cullMask = 0xffffffff;
    _cullMaskLeft = 0xffffffff;
    _cullMaskRight = 0xffffffff;

    // override during testing
    _computeNearFar = COMPUTE_NEAR_FAR_USING_PRIMITIVES;
    _nearFarRatio = 0.0005f;
}

void CullSettings::setCullSettings(const CullSettings& settings)
{
    _computeNearFar = settings._computeNearFar;
    _nearFarRatio = settings._nearFarRatio;
    _impostorActive = settings._impostorActive;
    _depthSortImpostorSprites = settings._depthSortImpostorSprites;
    _impostorPixelErrorThreshold = settings._impostorPixelErrorThreshold;
    _numFramesToKeepImpostorSprites = settings._numFramesToKeepImpostorSprites;
    _cullMask = settings._cullMask;
    _cullMaskLeft = settings._cullMaskLeft;
    _cullMaskRight = settings._cullMaskRight;
    _cullingMode = settings._cullingMode;
    _LODScale = settings._LODScale;
    _smallFeatureCullingPixelSize = settings._smallFeatureCullingPixelSize;
}
<commit_msg>Changed the default near far calculation mode so that it uses the fine grained computation of near/far.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osg/CullSettings>

using namespace osg;

void CullSettings::setDefaults()
{
    _cullingMode = DEFAULT_CULLING;
    _LODScale = 1.0f;
    _smallFeatureCullingPixelSize = 2.0f;

    _computeNearFar = COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES;
    _nearFarRatio = 0.0005f;
    _impostorActive = true;
    _depthSortImpostorSprites = false;
    _impostorPixelErrorThreshold = 4.0f;
    _numFramesToKeepImpostorSprites = 10;
    _cullMask = 0xffffffff;
    _cullMaskLeft = 0xffffffff;
    _cullMaskRight = 0xffffffff;

    // override during testing
    _computeNearFar = COMPUTE_NEAR_FAR_USING_PRIMITIVES;
    _nearFarRatio = 0.00005f;
}

void CullSettings::setCullSettings(const CullSettings& settings)
{
    _computeNearFar = settings._computeNearFar;
    _nearFarRatio = settings._nearFarRatio;
    _impostorActive = settings._impostorActive;
    _depthSortImpostorSprites = settings._depthSortImpostorSprites;
    _impostorPixelErrorThreshold = settings._impostorPixelErrorThreshold;
    _numFramesToKeepImpostorSprites = settings._numFramesToKeepImpostorSprites;
    _cullMask = settings._cullMask;
    _cullMaskLeft = settings._cullMaskLeft;
    _cullMaskRight = settings._cullMaskRight;
    _cullingMode = settings._cullingMode;
    _LODScale = settings._LODScale;
    _smallFeatureCullingPixelSize = settings._smallFeatureCullingPixelSize;
}
<|endoftext|>


<commit_before>#include <osgSim/ScalarBar>
#include <osgText/Text>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/PolygonOffset>
#include <sstream>

using namespace osgSim;

ScalarBar::~ScalarBar()
{
}

std::string ScalarBar::ScalarPrinter::printScalar(float scalar)
{
    std::stringstream ostr;
    ostr<<scalar;
    return ostr.str();
}

void ScalarBar::setNumColors(int numColors)
{
    _numColors = numColors;
    createDrawables();
}

int ScalarBar::getNumColors() const
{
    return _numColors;
}

void ScalarBar::setNumLabels(int numLabels)
{
    _numLabels = numLabels;
    createDrawables();
}

int ScalarBar::getNumLabels() const
{
    return _numLabels;
}

void ScalarBar::setScalarsToColors(ScalarsToColors* stc)
{
    _stc = stc;
    createDrawables();
}

const ScalarsToColors* ScalarBar::getScalarsToColors() const
{
    return _stc.get();
}

void ScalarBar::setTitle(const std::string& title)
{
    _title = title;
    createDrawables();
}

const std::string& ScalarBar::getTitle() const
{
    return _title;
}

void ScalarBar::setPosition(const osg::Vec3& pos)
{
    _position = pos;
    createDrawables();
}

void ScalarBar::setWidth(float width)
{
    _width = width;
    createDrawables();
}

void ScalarBar::setOrientation(ScalarBar::Orientation orientation)
{
    _orientation = orientation;
    createDrawables();
}

ScalarBar::Orientation ScalarBar::getOrientation() const
{
    return _orientation;
}

void ScalarBar::setAspectRatio(float aspectRatio)
{
    _aspectRatio = aspectRatio;
    createDrawables();
}

float ScalarBar::getAspectRatio() const
{
    return _aspectRatio;
}

void ScalarBar::setScalarPrinter(ScalarPrinter* sp)
{
    _sp = sp;
    createDrawables();
}

const ScalarBar::ScalarPrinter* ScalarBar::getScalarPrinter() const
{
    return _sp.get();
}

void ScalarBar::setTextProperties(const TextProperties& tp)
{
    _textProperties = tp;
    createDrawables();
}

const ScalarBar::TextProperties& ScalarBar::getTextProperties() const
{
    return _textProperties;
}

void ScalarBar::createDrawables()
{
    // Remove any existing Drawables
    removeDrawables(0, getNumDrawables());

    if (_numColors==0) return;

    osg::Matrix matrix;
    if(_orientation==HORIZONTAL)
    {
        matrix = osg::Matrix::translate(_position);
    }
    else
    {
        matrix = osg::Matrix::rotate(osg::DegreesToRadians(90.0f),0.0f,0.0f,1.0f) * osg::Matrix::translate(_position);
    }

    // 1. First the bar
    // =================
    osg::ref_ptr<osg::Geometry> bar = new osg::Geometry();

    // Create the bar - created in 'real' coordinate space the moment,
    // with xyz values reflecting those of the actual scalar values in play.
    // FIXME: Consider positioning at origin! Should be easy enough to do.

    // Vertices
    osg::ref_ptr<osg::Vec3Array> vs(new osg::Vec3Array);
    vs->reserve(4*_numColors);

    float incr = (_stc->getMax() - _stc->getMin()) / _numColors;
    float xincr = (_width) / _numColors;
    float arOffset = _width * _aspectRatio;

    int i;
    for(i=1; i<=_numColors; ++i)
    {
        vs->push_back(osg::Vec3((i-1) * xincr, 0.0f,     0.0f)*matrix);
        vs->push_back(osg::Vec3((i-1) * xincr, arOffset, 0.0f)*matrix);
        vs->push_back(osg::Vec3(i     * xincr, arOffset, 0.0f)*matrix);
        vs->push_back(osg::Vec3(i     * xincr, 0.0f,     0.0f)*matrix);
    }
    bar->setVertexArray(vs.get());

    // Colours
    osg::ref_ptr<osg::Vec4Array> cs(new osg::Vec4Array);
    cs->reserve(4*_numColors);
    const float halfIncr = incr*0.5;
    for(i=0; i<_numColors; ++i)
    {
        // We add half an increment to the color look-up to get the color
        // square in the middle of the 'block'.
        osg::Vec4 c = _stc->getColor(_stc->getMin() + (i*incr)  + halfIncr);
        cs->push_back(c);
        cs->push_back(c);
        cs->push_back(c);
        cs->push_back(c);
    }

    bar->setColorArray(cs.get(), osg::Array::BIND_PER_VERTEX);

    // Normal
    osg::ref_ptr<osg::Vec3Array> ns(new osg::Vec3Array);
    ns->push_back(osg::Matrix::transform3x3(osg::Vec3(0.0f,0.0f,1.0f),matrix));
    bar->setNormalArray(ns.get(), osg::Array::BIND_OVERALL);

    // The Quad strip that represents the bar
    bar->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,vs->size()));
    bar->getOrCreateStateSet()->setAttributeAndModes( new osg::PolygonOffset(1,1),
                            osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON );

    addDrawable(bar.get());

#define CHARACTER_OFFSET_FACTOR (0.3f)

    // 2. Then the text labels
    // =======================

    // Check the character size, if it's 0, estimate a good character size
    float characterSize = _textProperties._characterSize;
    if(characterSize == 0) characterSize = _width * 0.03f;

    osgText::Font* font = osgText::readFontFile(_textProperties._fontFile.c_str());

    std::vector<osgText::Text*> texts(_numLabels);      // We'll need to collect pointers to these for later
    float labelIncr = (_numLabels>0) ? (_stc->getMax()-_stc->getMin())/(_numLabels-1) : 0.0f;
    float labelxIncr = (_numLabels>0) ? (_width)/(_numLabels-1) : 0.0f;
    const float labelStickStartY = _orientation==HORIZONTAL ? arOffset : 0;
    const float labelY = labelStickStartY +
        (_orientation==HORIZONTAL ?  characterSize : -characterSize) * CHARACTER_OFFSET_FACTOR;

    for(i=0; i<_numLabels; ++i)
    {
        osgText::Text* text = new osgText::Text;
        text->setFont(font);
        text->setColor(_textProperties._color);
        text->setFontResolution(_textProperties._fontResolution.first,_textProperties._fontResolution.second);
        text->setCharacterSize(characterSize);
        text->setText(_sp->printScalar(_stc->getMin()+(i*labelIncr)));

        text->setPosition(osg::Vec3((i*labelxIncr), labelY, 0.0f)*matrix);
        text->setAlignment( (_orientation==HORIZONTAL) ? osgText::Text::CENTER_BASE_LINE : osgText::Text::LEFT_CENTER);

        addDrawable(text);

        texts[i] = text;
    }

    // 3. The title
    // ============

    if(_title != "")
    {
        osgText::Text* text = new osgText::Text;
        text->setFont(font);
        text->setColor(_textProperties._color);
        text->setFontResolution(_textProperties._fontResolution.first,_textProperties._fontResolution.second);
        text->setCharacterSize(characterSize);
        text->setText(_title);

        osg::Vec3 titlePos;
        if ( _orientation==HORIZONTAL )
        {
            const float titleY = (_numLabels>0) ? labelY + characterSize : labelY;
            titlePos = osg::Vec3((_width/2.0f), titleY, 0.0f);
        }
        else
        {
            titlePos = osg::Vec3(_width+characterSize*0.5, arOffset*0.5, 0 );
        }

        // Position the title at the middle of the bar above any labels.
        text->setPosition(titlePos*matrix);
        text->setAlignment(
            _orientation==HORIZONTAL ? osgText::Text::CENTER_BASE_LINE : osgText::Text::CENTER_BOTTOM);

        addDrawable(text);
    }

    // 4. The rectangular border and sticks
    // ====================================

    osg::ref_ptr<osg::Vec3Array> annotVertices = new osg::Vec3Array;

    //Border
    annotVertices->push_back( osg::Vec3(0.0f,0.0f,0.0f) * matrix  );
    annotVertices->push_back( osg::Vec3(0.0f,arOffset,0.0f) * matrix  );

    annotVertices->push_back( osg::Vec3(0.0f,arOffset,0.0f) * matrix  );
    annotVertices->push_back( osg::Vec3(_width,arOffset,0.0f) * matrix  );

    annotVertices->push_back( osg::Vec3(_width,arOffset,0.0f) * matrix  );
    annotVertices->push_back( osg::Vec3(_width,0.0f,0.0f) * matrix  );

    annotVertices->push_back( osg::Vec3(_width,0.0f,0.0f) * matrix  );
    annotVertices->push_back( osg::Vec3(0.0f,0.0f,0.0f) * matrix  );

    //Sticks
    for(i=0; i<_numLabels; ++i)
    {
        const osg::Vec3 p1(osg::Vec3((i*labelxIncr), labelStickStartY, 0.0f)*matrix);
        const osg::Vec3 p2(osg::Vec3((i*labelxIncr), labelY, 0.0f)*matrix);
        annotVertices->push_back( p1 );
        annotVertices->push_back( p2 );
    }

    osg::ref_ptr<osg::Geometry> annotationGeom = new osg::Geometry();
    annotationGeom->addPrimitiveSet( new osg::DrawArrays(GL_LINES,0,annotVertices->size()) );
    annotationGeom->setVertexArray( annotVertices.get() );
    osg::ref_ptr<osg::Material> annotMaterial = new osg::Material;
    annotMaterial->setDiffuse( osg::Material::FRONT, _textProperties._color );
    annotationGeom->getOrCreateStateSet()->setAttribute( annotMaterial.get() );

    addDrawable( annotationGeom.get() );
}
<commit_msg>From Jamie Robertson, "I've been using osgSim::ScalarBar to display fixed range color values (e.g. red from 1-2, green from 3-4 etc), by setting the _numColors the same as the number of actual colors in the ColorRange.<commit_after>#include <osgSim/ScalarBar>
#include <osgText/Text>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/PolygonOffset>
#include <sstream>

using namespace osgSim;

ScalarBar::~ScalarBar()
{
}

std::string ScalarBar::ScalarPrinter::printScalar(float scalar)
{
    std::stringstream ostr;
    ostr<<scalar;
    return ostr.str();
}

void ScalarBar::setNumColors(int numColors)
{
    _numColors = numColors;
    createDrawables();
}

int ScalarBar::getNumColors() const
{
    return _numColors;
}

void ScalarBar::setNumLabels(int numLabels)
{
    _numLabels = numLabels;
    createDrawables();
}

int ScalarBar::getNumLabels() const
{
    return _numLabels;
}

void ScalarBar::setScalarsToColors(ScalarsToColors* stc)
{
    _stc = stc;
    createDrawables();
}

const ScalarsToColors* ScalarBar::getScalarsToColors() const
{
    return _stc.get();
}

void ScalarBar::setTitle(const std::string& title)
{
    _title = title;
    createDrawables();
}

const std::string& ScalarBar::getTitle() const
{
    return _title;
}

void ScalarBar::setPosition(const osg::Vec3& pos)
{
    _position = pos;
    createDrawables();
}

void ScalarBar::setWidth(float width)
{
    _width = width;
    createDrawables();
}

void ScalarBar::setOrientation(ScalarBar::Orientation orientation)
{
    _orientation = orientation;
    createDrawables();
}

ScalarBar::Orientation ScalarBar::getOrientation() const
{
    return _orientation;
}

void ScalarBar::setAspectRatio(float aspectRatio)
{
    _aspectRatio = aspectRatio;
    createDrawables();
}

float ScalarBar::getAspectRatio() const
{
    return _aspectRatio;
}

void ScalarBar::setScalarPrinter(ScalarPrinter* sp)
{
    _sp = sp;
    createDrawables();
}

const ScalarBar::ScalarPrinter* ScalarBar::getScalarPrinter() const
{
    return _sp.get();
}

void ScalarBar::setTextProperties(const TextProperties& tp)
{
    _textProperties = tp;
    createDrawables();
}

const ScalarBar::TextProperties& ScalarBar::getTextProperties() const
{
    return _textProperties;
}

void ScalarBar::createDrawables()
{
    // Remove any existing Drawables
    removeDrawables(0, getNumDrawables());

    if (_numColors==0) return;

    osg::Matrix matrix;
    if(_orientation==HORIZONTAL)
    {
        matrix = osg::Matrix::translate(_position);
    }
    else
    {
        matrix = osg::Matrix::rotate(osg::DegreesToRadians(90.0f),0.0f,0.0f,1.0f) * osg::Matrix::translate(_position);
    }

    // 1. First the bar
    // =================
    osg::ref_ptr<osg::Geometry> bar = new osg::Geometry();

    // Create the bar - created in 'real' coordinate space the moment,
    // with xyz values reflecting those of the actual scalar values in play.
    // FIXME: Consider positioning at origin! Should be easy enough to do.

    // Vertices
    osg::ref_ptr<osg::Vec3Array> vs(new osg::Vec3Array);
    vs->reserve(4*_numColors);

    float incr = (_stc->getMax() - _stc->getMin()) / _numColors;
    float xincr = (_width) / _numColors;
    float arOffset = _width * _aspectRatio;

    int i;
    for(i=1; i<=_numColors; ++i)
    {
        vs->push_back(osg::Vec3((i-1) * xincr, 0.0f,     0.0f)*matrix);
        vs->push_back(osg::Vec3((i-1) * xincr, arOffset, 0.0f)*matrix);
        vs->push_back(osg::Vec3(i     * xincr, arOffset, 0.0f)*matrix);
        vs->push_back(osg::Vec3(i     * xincr, 0.0f,     0.0f)*matrix);
    }
    bar->setVertexArray(vs.get());

    // Colours
    osg::ref_ptr<osg::Vec4Array> cs(new osg::Vec4Array);
    cs->reserve(4*_numColors);
    const float halfIncr = incr*0.5;
    // Check whether to use interpolated colors or retain the original
    // color values if _numColors equals the number of ColorRange colors defined
    ColorRange *cr = dynamic_cast<ColorRange*>(_stc.get());
    bool fixedColors = cr && (_numColors == static_cast<int>(cr->getColors().size()));
    for (i = 0; i<_numColors; ++i)
    {
        // We add half an increment to the color look-up to get the color
        // square in the middle of the 'block' unless using fixed colors.
        osg::Vec4 c = fixedColors ? cr->getColors()[i] : _stc->getColor(_stc->getMin() + (i*incr) + halfIncr);
        cs->push_back(c);
        cs->push_back(c);
        cs->push_back(c);
        cs->push_back(c);
    }

    bar->setColorArray(cs.get(), osg::Array::BIND_PER_VERTEX);

    // Normal
    osg::ref_ptr<osg::Vec3Array> ns(new osg::Vec3Array);
    ns->push_back(osg::Matrix::transform3x3(osg::Vec3(0.0f,0.0f,1.0f),matrix));
    bar->setNormalArray(ns.get(), osg::Array::BIND_OVERALL);

    // The Quad strip that represents the bar
    bar->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,vs->size()));
    bar->getOrCreateStateSet()->setAttributeAndModes( new osg::PolygonOffset(1,1),
                            osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON );

    addDrawable(bar.get());

#define CHARACTER_OFFSET_FACTOR (0.3f)

    // 2. Then the text labels
    // =======================

    // Check the character size, if it's 0, estimate a good character size
    float characterSize = _textProperties._characterSize;
    if(characterSize == 0) characterSize = _width * 0.03f;

    osgText::Font* font = osgText::readFontFile(_textProperties._fontFile.c_str());

    std::vector<osgText::Text*> texts(_numLabels);      // We'll need to collect pointers to these for later
    float labelIncr = (_numLabels>0) ? (_stc->getMax()-_stc->getMin())/(_numLabels-1) : 0.0f;
    float labelxIncr = (_numLabels>0) ? (_width)/(_numLabels-1) : 0.0f;
    const float labelStickStartY = _orientation==HORIZONTAL ? arOffset : 0;
    const float labelY = labelStickStartY +
        (_orientation==HORIZONTAL ?  characterSize : -characterSize) * CHARACTER_OFFSET_FACTOR;

    for(i=0; i<_numLabels; ++i)
    {
        osgText::Text* text = new osgText::Text;
        text->setFont(font);
        text->setColor(_textProperties._color);
        text->setFontResolution(_textProperties._fontResolution.first,_textProperties._fontResolution.second);
        text->setCharacterSize(characterSize);
        text->setText(_sp->printScalar(_stc->getMin()+(i*labelIncr)));

        text->setPosition(osg::Vec3((i*labelxIncr), labelY, 0.0f)*matrix);
        text->setAlignment( (_orientation==HORIZONTAL) ? osgText::Text::CENTER_BASE_LINE : osgText::Text::LEFT_CENTER);

        addDrawable(text);

        texts[i] = text;
    }

    // 3. The title
    // ============

    if(_title != "")
    {
        osgText::Text* text = new osgText::Text;
        text->setFont(font);
        text->setColor(_textProperties._color);
        text->setFontResolution(_textProperties._fontResolution.first,_textProperties._fontResolution.second);
        text->setCharacterSize(characterSize);
        text->setText(_title);

        osg::Vec3 titlePos;
        if ( _orientation==HORIZONTAL )
        {
            const float titleY = (_numLabels>0) ? labelY + characterSize : labelY;
            titlePos = osg::Vec3((_width/2.0f), titleY, 0.0f);
        }
        else
        {
            titlePos = osg::Vec3(_width+characterSize*0.5, arOffset*0.5, 0 );
        }

        // Position the title at the middle of the bar above any labels.
        text->setPosition(titlePos*matrix);
        text->setAlignment(
            _orientation==HORIZONTAL ? osgText::Text::CENTER_BASE_LINE : osgText::Text::CENTER_BOTTOM);

        addDrawable(text);
    }

    // 4. The rectangular border and sticks
    // ====================================

    osg::ref_ptr<osg::Vec3Array> annotVertices = new osg::Vec3Array;

    //Border
    annotVertices->push_back( osg::Vec3(0.0f,0.0f,0.0f) * matrix  );
    annotVertices->push_back( osg::Vec3(0.0f,arOffset,0.0f) * matrix  );

    annotVertices->push_back( osg::Vec3(0.0f,arOffset,0.0f) * matrix  );
    annotVertices->push_back( osg::Vec3(_width,arOffset,0.0f) * matrix  );

    annotVertices->push_back( osg::Vec3(_width,arOffset,0.0f) * matrix  );
    annotVertices->push_back( osg::Vec3(_width,0.0f,0.0f) * matrix  );

    annotVertices->push_back( osg::Vec3(_width,0.0f,0.0f) * matrix  );
    annotVertices->push_back( osg::Vec3(0.0f,0.0f,0.0f) * matrix  );

    //Sticks
    for(i=0; i<_numLabels; ++i)
    {
        const osg::Vec3 p1(osg::Vec3((i*labelxIncr), labelStickStartY, 0.0f)*matrix);
        const osg::Vec3 p2(osg::Vec3((i*labelxIncr), labelY, 0.0f)*matrix);
        annotVertices->push_back( p1 );
        annotVertices->push_back( p2 );
    }

    osg::ref_ptr<osg::Geometry> annotationGeom = new osg::Geometry();
    annotationGeom->addPrimitiveSet( new osg::DrawArrays(GL_LINES,0,annotVertices->size()) );
    annotationGeom->setVertexArray( annotVertices.get() );
    osg::ref_ptr<osg::Material> annotMaterial = new osg::Material;
    annotMaterial->setDiffuse( osg::Material::FRONT, _textProperties._color );
    annotationGeom->getOrCreateStateSet()->setAttribute( annotMaterial.get() );

    addDrawable( annotationGeom.get() );
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 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 "ui/gfx/canvas_skia.h"

#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "ui/base/text/text_elider.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/render_text.h"
#include "ui/gfx/skia_util.h"

namespace {

// Based on |flags| and |text| content, returns whether text should be
// rendered right-to-left.
bool IsTextRTL(int flags, const string16& text) {
  if (flags & gfx::Canvas::FORCE_RTL_DIRECTIONALITY)
    return true;
  if (flags & gfx::Canvas::FORCE_LTR_DIRECTIONALITY)
    return false;
  return base::i18n::IsRTL() && base::i18n::StringContainsStrongRTLChars(text);
}

// Checks each pixel immediately adjacent to the given pixel in the bitmap. If
// any of them are not the halo color, returns true. This defines the halo of
// pixels that will appear around the text. Note that we have to check each
// pixel against both the halo color and transparent since |DrawStringWithHalo|
// will modify the bitmap as it goes, and cleared pixels shouldn't count as
// changed.
bool PixelShouldGetHalo(const SkBitmap& bitmap,
                        int x, int y,
                        SkColor halo_color) {
  if (x > 0 &&
      *bitmap.getAddr32(x - 1, y) != halo_color &&
      *bitmap.getAddr32(x - 1, y) != 0)
    return true;  // Touched pixel to the left.
  if (x < bitmap.width() - 1 &&
      *bitmap.getAddr32(x + 1, y) != halo_color &&
      *bitmap.getAddr32(x + 1, y) != 0)
    return true;  // Touched pixel to the right.
  if (y > 0 &&
      *bitmap.getAddr32(x, y - 1) != halo_color &&
      *bitmap.getAddr32(x, y - 1) != 0)
    return true;  // Touched pixel above.
  if (y < bitmap.height() - 1 &&
      *bitmap.getAddr32(x, y + 1) != halo_color &&
      *bitmap.getAddr32(x, y + 1) != 0)
    return true;  // Touched pixel below.
  return false;
}

// Apply vertical alignment per |flags|. Returns y-coordinate delta.
int VAlignText(const gfx::Font& font,
               int line_count,
               int flags,
               int available_height) {
  const int text_size = font.GetFontSize();

  if (flags & gfx::Canvas::TEXT_VALIGN_TOP)
    return text_size;

  if (flags & gfx::Canvas::TEXT_VALIGN_BOTTOM) {
    // Note: The -1 was chosen empirically to match the existing GDI code.
    int offset = available_height + text_size - font.GetHeight() - 1;
    if (line_count > 1)
      offset -= (line_count * text_size);
    return offset;
  }

  // Default case: TEXT_VALIGN_MIDDLE.
  // Note: The +1 below and the -2 further down were chosen empirically to match
  // the alignment and rounding in the existing GDI code.
  int double_offset = available_height + text_size + 1;
  if (line_count > 1)
    double_offset -= (line_count * text_size);
  return double_offset / 2 - 2;
}

// Updates |render_text| from the specified parameters.
void UpdateRenderText(gfx::RenderText* render_text,
                      const gfx::Rect& rect,
                      const string16& text,
                      const gfx::Font& font,
                      int flags,
                      SkColor color) {
  int accelerated_char_pos = -1;
  int accelerated_char_span = 0;
  string16 transformed_text = text;

  // Strip accelerator character prefixes.
  if (flags & (gfx::Canvas::SHOW_PREFIX | gfx::Canvas::HIDE_PREFIX)) {
    transformed_text = gfx::RemoveAcceleratorChar(text,
                                                  '&',
                                                  &accelerated_char_pos,
                                                  &accelerated_char_span);
  }

  render_text->SetFontList(gfx::FontList(font));
  render_text->SetText(transformed_text);
  render_text->SetCursorEnabled(false);

  gfx::Rect display_rect = rect;
  display_rect.Offset(0, -font.GetFontSize());
  display_rect.set_height(font.GetHeight());
  render_text->SetDisplayRect(display_rect);

  if (flags & gfx::Canvas::TEXT_ALIGN_RIGHT)
    render_text->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
  else if (flags & gfx::Canvas::TEXT_ALIGN_CENTER)
    render_text->SetHorizontalAlignment(gfx::ALIGN_CENTER);
  else
    render_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);

  gfx::StyleRange style;
  style.foreground = color;
  style.font_style = font.GetStyle();
  if (font.GetStyle() & gfx::Font::UNDERLINED)
    style.underline = true;
  render_text->set_default_style(style);
  render_text->ApplyDefaultStyle();

  // Underline the accelerator char, if present.
  if ((flags & gfx::Canvas::SHOW_PREFIX) && accelerated_char_pos != -1 &&
      !style.underline) {
    gfx::StyleRange underline_style = style;
    int accelerated_char_end = accelerated_char_pos + accelerated_char_span;
    underline_style.range.set_start(accelerated_char_pos);
    underline_style.range.set_end(accelerated_char_end);
    underline_style.underline = true;
    render_text->ApplyStyleRange(underline_style);
  }
}

}  // anonymous namespace

namespace gfx {

// static
void CanvasSkia::SizeStringInt(const string16& text,
                               const gfx::Font& font,
                               int* width, int* height,
                               int flags) {
  DCHECK_GE(*width, 0);
  DCHECK_GE(*height, 0);

  if ((flags & MULTI_LINE) && *width != 0) {
    ui::WordWrapBehavior wrap_behavior = ui::TRUNCATE_LONG_WORDS;
    if (flags & CHARACTER_BREAK)
      wrap_behavior = ui::WRAP_LONG_WORDS;
    else if (!(flags & NO_ELLIPSIS))
      wrap_behavior = ui::ELIDE_LONG_WORDS;

    gfx::Rect rect(*width, INT_MAX);
    std::vector<string16> strings;
    ui::ElideRectangleText(text, font, rect.width(), rect.height(),
                           wrap_behavior, &strings);
    scoped_ptr<RenderText> render_text(RenderText::CreateRenderText());
    UpdateRenderText(render_text.get(), rect, string16(), font, flags, 0);

    int h = 0;
    int w = 0;
    for (size_t i = 0; i < strings.size(); ++i) {
      if (flags & (SHOW_PREFIX | HIDE_PREFIX))
        strings[i] = gfx::RemoveAcceleratorChar(strings[i], '&', NULL, NULL);
      render_text->SetText(strings[i]);
      w = std::max(w, render_text->GetStringWidth());
      h += font.GetHeight();
    }
    *width = w;
    *height = h;
  } else {
    // If the string is too long, the call by |RenderTextWin| to |ScriptShape()|
    // will inexplicably fail with result E_INVALIDARG. Guard against this.
    const size_t kMaxRenderTextLength = 5000;
    if (text.length() >= kMaxRenderTextLength) {
      *width = text.length() * font.GetAverageCharacterWidth();
    } else {
      scoped_ptr<RenderText> render_text(RenderText::CreateRenderText());
      gfx::Rect rect(*width, *height);
      UpdateRenderText(render_text.get(), rect, text, font, flags, 0);
      *width = render_text->GetStringWidth();
    }
    *height = font.GetHeight();
  }
}

void CanvasSkia::DrawStringInt(const string16& text,
                               const gfx::Font& font,
                               const SkColor& color,
                               int x, int y, int w, int h,
                               int flags) {
  if (!IntersectsClipRectInt(x, y, w, h))
    return;

  // TODO(asvitkine): On Windows, MULTI_LINE implies top alignment.
  //                  http://crbug.com/107357
  if (flags & MULTI_LINE) {
    flags &= ~(TEXT_VALIGN_MIDDLE | TEXT_VALIGN_BOTTOM);
    flags |= TEXT_VALIGN_TOP;
  }

  gfx::Rect rect(x, y, w, h);
  canvas_->save(SkCanvas::kClip_SaveFlag);
  ClipRect(rect);

  string16 adjusted_text = text;
  if (IsTextRTL(flags, text))
    base::i18n::AdjustStringForLocaleDirection(&adjusted_text);

  scoped_ptr<RenderText> render_text(RenderText::CreateRenderText());

  if (flags & MULTI_LINE) {
    ui::WordWrapBehavior wrap_behavior = ui::IGNORE_LONG_WORDS;
    if (flags & CHARACTER_BREAK)
      wrap_behavior = ui::WRAP_LONG_WORDS;
    else if (!(flags & NO_ELLIPSIS))
      wrap_behavior = ui::ELIDE_LONG_WORDS;

    std::vector<string16> strings;
    ui::ElideRectangleText(adjusted_text, font, w, h, wrap_behavior,
                           &strings);

    rect.Offset(0, VAlignText(font, strings.size(), flags, h));
    for (size_t i = 0; i < strings.size(); i++) {
      UpdateRenderText(render_text.get(), rect, strings[i], font, flags, color);
      render_text->Draw(this);
      rect.Offset(0, font.GetHeight());
    }
  } else {
    if (!(flags & NO_ELLIPSIS))
      adjusted_text = ui::ElideText(adjusted_text, font, w, ui::ELIDE_AT_END);

    rect.Offset(0, VAlignText(font, 1, flags, h));
    UpdateRenderText(render_text.get(), rect, adjusted_text, font, flags,
                     color);
    render_text->Draw(this);
  }

  canvas_->restore();
}

void CanvasSkia::DrawStringWithHalo(const string16& text,
                                    const gfx::Font& font,
                                    const SkColor& text_color,
                                    const SkColor& halo_color_in,
                                    int x, int y, int w, int h,
                                    int flags) {
  // Some callers will have semitransparent halo colors, which we don't handle
  // (since the resulting image can have 1-bit transparency only).
  SkColor halo_color = halo_color_in | 0xFF000000;

  // Create a temporary buffer filled with the halo color. It must leave room
  // for the 1-pixel border around the text.
  gfx::Size size(w + 2, h + 2);
  CanvasSkia text_canvas(size, true);
  SkPaint bkgnd_paint;
  bkgnd_paint.setColor(halo_color);
  text_canvas.DrawRect(gfx::Rect(size), bkgnd_paint);

  // Draw the text into the temporary buffer. This will have correct
  // ClearType since the background color is the same as the halo color.
  text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags);

  uint32_t halo_premul = SkPreMultiplyColor(halo_color);
  SkBitmap& text_bitmap = const_cast<SkBitmap&>(
      skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(true));

  for (int cur_y = 0; cur_y < h + 2; cur_y++) {
    uint32_t* text_row = text_bitmap.getAddr32(0, cur_y);
    for (int cur_x = 0; cur_x < w + 2; cur_x++) {
      if (text_row[cur_x] == halo_premul) {
        // This pixel was not touched by the text routines. See if it borders
        // a touched pixel in any of the 4 directions (not diagonally).
        if (!PixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul))
          text_row[cur_x] = 0;  // Make transparent.
      } else {
        text_row[cur_x] |= 0xff << SK_A32_SHIFT;  // Make opaque.
      }
    }
  }

  // Draw the halo bitmap with blur.
  DrawBitmapInt(text_bitmap, x - 1, y - 1);
}

void CanvasSkia::DrawFadeTruncatingString(
      const string16& text,
      CanvasSkia::TruncateFadeMode truncate_mode,
      size_t desired_characters_to_truncate_from_head,
      const gfx::Font& font,
      const SkColor& color,
      const gfx::Rect& display_rect) {
  int flags = NO_ELLIPSIS;

  // If the whole string fits in the destination then just draw it directly.
  if (GetStringWidth(text, font) <= display_rect.width()) {
    DrawStringInt(text, font, color, display_rect.x(), display_rect.y(),
                  display_rect.width(), display_rect.height(), flags);
    return;
  }

  scoped_ptr<RenderText> render_text(RenderText::CreateRenderText());
  string16 clipped_text = text;
  const bool is_rtl = IsTextRTL(flags, text);
  if (is_rtl)
    base::i18n::AdjustStringForLocaleDirection(&clipped_text);

  switch (truncate_mode) {
    case TruncateFadeTail:
      render_text->set_fade_tail(true);
      if (is_rtl)
        flags |= TEXT_ALIGN_RIGHT;
      break;
    case TruncateFadeHead:
      render_text->set_fade_head(true);
      if (!is_rtl)
        flags |= TEXT_ALIGN_RIGHT;
      break;
    case TruncateFadeHeadAndTail:
      DCHECK_GT(desired_characters_to_truncate_from_head, 0u);
      // Due to the fade effect the first character is hard to see.
      // We want to make sure that the first character starting at
      // |desired_characters_to_truncate_from_head| is readable so we reduce
      // the offset by a little bit.
      desired_characters_to_truncate_from_head =
          std::max<int>(0, desired_characters_to_truncate_from_head - 2);

      if (desired_characters_to_truncate_from_head) {
        // Make sure to clip the text at a UTF16 boundary.
        U16_SET_CP_LIMIT(text.data(), 0,
                         desired_characters_to_truncate_from_head,
                         text.length());
        clipped_text = text.substr(desired_characters_to_truncate_from_head);
      }

      render_text->set_fade_tail(true);
      render_text->set_fade_head(true);
      break;
  }

  gfx::Rect text_rect = display_rect;
  text_rect.Offset(0, VAlignText(font, 1, flags, display_rect.height()));
  UpdateRenderText(render_text.get(), text_rect, clipped_text, font, flags,
                   color);

  canvas_->save(SkCanvas::kClip_SaveFlag);
  ClipRect(display_rect);
  render_text->Draw(this);
  canvas_->restore();
}

}  // namespace gfx
<commit_msg>chmod a-x on canvas_skia_skia.cc<commit_after>// Copyright (c) 2012 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 "ui/gfx/canvas_skia.h"

#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "ui/base/text/text_elider.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/render_text.h"
#include "ui/gfx/skia_util.h"

namespace {

// Based on |flags| and |text| content, returns whether text should be
// rendered right-to-left.
bool IsTextRTL(int flags, const string16& text) {
  if (flags & gfx::Canvas::FORCE_RTL_DIRECTIONALITY)
    return true;
  if (flags & gfx::Canvas::FORCE_LTR_DIRECTIONALITY)
    return false;
  return base::i18n::IsRTL() && base::i18n::StringContainsStrongRTLChars(text);
}

// Checks each pixel immediately adjacent to the given pixel in the bitmap. If
// any of them are not the halo color, returns true. This defines the halo of
// pixels that will appear around the text. Note that we have to check each
// pixel against both the halo color and transparent since |DrawStringWithHalo|
// will modify the bitmap as it goes, and cleared pixels shouldn't count as
// changed.
bool PixelShouldGetHalo(const SkBitmap& bitmap,
                        int x, int y,
                        SkColor halo_color) {
  if (x > 0 &&
      *bitmap.getAddr32(x - 1, y) != halo_color &&
      *bitmap.getAddr32(x - 1, y) != 0)
    return true;  // Touched pixel to the left.
  if (x < bitmap.width() - 1 &&
      *bitmap.getAddr32(x + 1, y) != halo_color &&
      *bitmap.getAddr32(x + 1, y) != 0)
    return true;  // Touched pixel to the right.
  if (y > 0 &&
      *bitmap.getAddr32(x, y - 1) != halo_color &&
      *bitmap.getAddr32(x, y - 1) != 0)
    return true;  // Touched pixel above.
  if (y < bitmap.height() - 1 &&
      *bitmap.getAddr32(x, y + 1) != halo_color &&
      *bitmap.getAddr32(x, y + 1) != 0)
    return true;  // Touched pixel below.
  return false;
}

// Apply vertical alignment per |flags|. Returns y-coordinate delta.
int VAlignText(const gfx::Font& font,
               int line_count,
               int flags,
               int available_height) {
  const int text_size = font.GetFontSize();

  if (flags & gfx::Canvas::TEXT_VALIGN_TOP)
    return text_size;

  if (flags & gfx::Canvas::TEXT_VALIGN_BOTTOM) {
    // Note: The -1 was chosen empirically to match the existing GDI code.
    int offset = available_height + text_size - font.GetHeight() - 1;
    if (line_count > 1)
      offset -= (line_count * text_size);
    return offset;
  }

  // Default case: TEXT_VALIGN_MIDDLE.
  // Note: The +1 below and the -2 further down were chosen empirically to match
  // the alignment and rounding in the existing GDI code.
  int double_offset = available_height + text_size + 1;
  if (line_count > 1)
    double_offset -= (line_count * text_size);
  return double_offset / 2 - 2;
}

// Updates |render_text| from the specified parameters.
void UpdateRenderText(gfx::RenderText* render_text,
                      const gfx::Rect& rect,
                      const string16& text,
                      const gfx::Font& font,
                      int flags,
                      SkColor color) {
  int accelerated_char_pos = -1;
  int accelerated_char_span = 0;
  string16 transformed_text = text;

  // Strip accelerator character prefixes.
  if (flags & (gfx::Canvas::SHOW_PREFIX | gfx::Canvas::HIDE_PREFIX)) {
    transformed_text = gfx::RemoveAcceleratorChar(text,
                                                  '&',
                                                  &accelerated_char_pos,
                                                  &accelerated_char_span);
  }

  render_text->SetFontList(gfx::FontList(font));
  render_text->SetText(transformed_text);
  render_text->SetCursorEnabled(false);

  gfx::Rect display_rect = rect;
  display_rect.Offset(0, -font.GetFontSize());
  display_rect.set_height(font.GetHeight());
  render_text->SetDisplayRect(display_rect);

  if (flags & gfx::Canvas::TEXT_ALIGN_RIGHT)
    render_text->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
  else if (flags & gfx::Canvas::TEXT_ALIGN_CENTER)
    render_text->SetHorizontalAlignment(gfx::ALIGN_CENTER);
  else
    render_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);

  gfx::StyleRange style;
  style.foreground = color;
  style.font_style = font.GetStyle();
  if (font.GetStyle() & gfx::Font::UNDERLINED)
    style.underline = true;
  render_text->set_default_style(style);
  render_text->ApplyDefaultStyle();

  // Underline the accelerator char, if present.
  if ((flags & gfx::Canvas::SHOW_PREFIX) && accelerated_char_pos != -1 &&
      !style.underline) {
    gfx::StyleRange underline_style = style;
    int accelerated_char_end = accelerated_char_pos + accelerated_char_span;
    underline_style.range.set_start(accelerated_char_pos);
    underline_style.range.set_end(accelerated_char_end);
    underline_style.underline = true;
    render_text->ApplyStyleRange(underline_style);
  }
}

}  // anonymous namespace

namespace gfx {

// static
void CanvasSkia::SizeStringInt(const string16& text,
                               const gfx::Font& font,
                               int* width, int* height,
                               int flags) {
  DCHECK_GE(*width, 0);
  DCHECK_GE(*height, 0);

  if ((flags & MULTI_LINE) && *width != 0) {
    ui::WordWrapBehavior wrap_behavior = ui::TRUNCATE_LONG_WORDS;
    if (flags & CHARACTER_BREAK)
      wrap_behavior = ui::WRAP_LONG_WORDS;
    else if (!(flags & NO_ELLIPSIS))
      wrap_behavior = ui::ELIDE_LONG_WORDS;

    gfx::Rect rect(*width, INT_MAX);
    std::vector<string16> strings;
    ui::ElideRectangleText(text, font, rect.width(), rect.height(),
                           wrap_behavior, &strings);
    scoped_ptr<RenderText> render_text(RenderText::CreateRenderText());
    UpdateRenderText(render_text.get(), rect, string16(), font, flags, 0);

    int h = 0;
    int w = 0;
    for (size_t i = 0; i < strings.size(); ++i) {
      if (flags & (SHOW_PREFIX | HIDE_PREFIX))
        strings[i] = gfx::RemoveAcceleratorChar(strings[i], '&', NULL, NULL);
      render_text->SetText(strings[i]);
      w = std::max(w, render_text->GetStringWidth());
      h += font.GetHeight();
    }
    *width = w;
    *height = h;
  } else {
    // If the string is too long, the call by |RenderTextWin| to |ScriptShape()|
    // will inexplicably fail with result E_INVALIDARG. Guard against this.
    const size_t kMaxRenderTextLength = 5000;
    if (text.length() >= kMaxRenderTextLength) {
      *width = text.length() * font.GetAverageCharacterWidth();
    } else {
      scoped_ptr<RenderText> render_text(RenderText::CreateRenderText());
      gfx::Rect rect(*width, *height);
      UpdateRenderText(render_text.get(), rect, text, font, flags, 0);
      *width = render_text->GetStringWidth();
    }
    *height = font.GetHeight();
  }
}

void CanvasSkia::DrawStringInt(const string16& text,
                               const gfx::Font& font,
                               const SkColor& color,
                               int x, int y, int w, int h,
                               int flags) {
  if (!IntersectsClipRectInt(x, y, w, h))
    return;

  // TODO(asvitkine): On Windows, MULTI_LINE implies top alignment.
  //                  http://crbug.com/107357
  if (flags & MULTI_LINE) {
    flags &= ~(TEXT_VALIGN_MIDDLE | TEXT_VALIGN_BOTTOM);
    flags |= TEXT_VALIGN_TOP;
  }

  gfx::Rect rect(x, y, w, h);
  canvas_->save(SkCanvas::kClip_SaveFlag);
  ClipRect(rect);

  string16 adjusted_text = text;
  if (IsTextRTL(flags, text))
    base::i18n::AdjustStringForLocaleDirection(&adjusted_text);

  scoped_ptr<RenderText> render_text(RenderText::CreateRenderText());

  if (flags & MULTI_LINE) {
    ui::WordWrapBehavior wrap_behavior = ui::IGNORE_LONG_WORDS;
    if (flags & CHARACTER_BREAK)
      wrap_behavior = ui::WRAP_LONG_WORDS;
    else if (!(flags & NO_ELLIPSIS))
      wrap_behavior = ui::ELIDE_LONG_WORDS;

    std::vector<string16> strings;
    ui::ElideRectangleText(adjusted_text, font, w, h, wrap_behavior,
                           &strings);

    rect.Offset(0, VAlignText(font, strings.size(), flags, h));
    for (size_t i = 0; i < strings.size(); i++) {
      UpdateRenderText(render_text.get(), rect, strings[i], font, flags, color);
      render_text->Draw(this);
      rect.Offset(0, font.GetHeight());
    }
  } else {
    if (!(flags & NO_ELLIPSIS))
      adjusted_text = ui::ElideText(adjusted_text, font, w, ui::ELIDE_AT_END);

    rect.Offset(0, VAlignText(font, 1, flags, h));
    UpdateRenderText(render_text.get(), rect, adjusted_text, font, flags,
                     color);
    render_text->Draw(this);
  }

  canvas_->restore();
}

void CanvasSkia::DrawStringWithHalo(const string16& text,
                                    const gfx::Font& font,
                                    const SkColor& text_color,
                                    const SkColor& halo_color_in,
                                    int x, int y, int w, int h,
                                    int flags) {
  // Some callers will have semitransparent halo colors, which we don't handle
  // (since the resulting image can have 1-bit transparency only).
  SkColor halo_color = halo_color_in | 0xFF000000;

  // Create a temporary buffer filled with the halo color. It must leave room
  // for the 1-pixel border around the text.
  gfx::Size size(w + 2, h + 2);
  CanvasSkia text_canvas(size, true);
  SkPaint bkgnd_paint;
  bkgnd_paint.setColor(halo_color);
  text_canvas.DrawRect(gfx::Rect(size), bkgnd_paint);

  // Draw the text into the temporary buffer. This will have correct
  // ClearType since the background color is the same as the halo color.
  text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags);

  uint32_t halo_premul = SkPreMultiplyColor(halo_color);
  SkBitmap& text_bitmap = const_cast<SkBitmap&>(
      skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(true));

  for (int cur_y = 0; cur_y < h + 2; cur_y++) {
    uint32_t* text_row = text_bitmap.getAddr32(0, cur_y);
    for (int cur_x = 0; cur_x < w + 2; cur_x++) {
      if (text_row[cur_x] == halo_premul) {
        // This pixel was not touched by the text routines. See if it borders
        // a touched pixel in any of the 4 directions (not diagonally).
        if (!PixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul))
          text_row[cur_x] = 0;  // Make transparent.
      } else {
        text_row[cur_x] |= 0xff << SK_A32_SHIFT;  // Make opaque.
      }
    }
  }

  // Draw the halo bitmap with blur.
  DrawBitmapInt(text_bitmap, x - 1, y - 1);
}

void CanvasSkia::DrawFadeTruncatingString(
      const string16& text,
      CanvasSkia::TruncateFadeMode truncate_mode,
      size_t desired_characters_to_truncate_from_head,
      const gfx::Font& font,
      const SkColor& color,
      const gfx::Rect& display_rect) {
  int flags = NO_ELLIPSIS;

  // If the whole string fits in the destination then just draw it directly.
  if (GetStringWidth(text, font) <= display_rect.width()) {
    DrawStringInt(text, font, color, display_rect.x(), display_rect.y(),
                  display_rect.width(), display_rect.height(), flags);
    return;
  }

  scoped_ptr<RenderText> render_text(RenderText::CreateRenderText());
  string16 clipped_text = text;
  const bool is_rtl = IsTextRTL(flags, text);
  if (is_rtl)
    base::i18n::AdjustStringForLocaleDirection(&clipped_text);

  switch (truncate_mode) {
    case TruncateFadeTail:
      render_text->set_fade_tail(true);
      if (is_rtl)
        flags |= TEXT_ALIGN_RIGHT;
      break;
    case TruncateFadeHead:
      render_text->set_fade_head(true);
      if (!is_rtl)
        flags |= TEXT_ALIGN_RIGHT;
      break;
    case TruncateFadeHeadAndTail:
      DCHECK_GT(desired_characters_to_truncate_from_head, 0u);
      // Due to the fade effect the first character is hard to see.
      // We want to make sure that the first character starting at
      // |desired_characters_to_truncate_from_head| is readable so we reduce
      // the offset by a little bit.
      desired_characters_to_truncate_from_head =
          std::max<int>(0, desired_characters_to_truncate_from_head - 2);

      if (desired_characters_to_truncate_from_head) {
        // Make sure to clip the text at a UTF16 boundary.
        U16_SET_CP_LIMIT(text.data(), 0,
                         desired_characters_to_truncate_from_head,
                         text.length());
        clipped_text = text.substr(desired_characters_to_truncate_from_head);
      }

      render_text->set_fade_tail(true);
      render_text->set_fade_head(true);
      break;
  }

  gfx::Rect text_rect = display_rect;
  text_rect.Offset(0, VAlignText(font, 1, flags, display_rect.height()));
  UpdateRenderText(render_text.get(), text_rect, clipped_text, font, flags,
                   color);

  canvas_->save(SkCanvas::kClip_SaveFlag);
  ClipRect(display_rect);
  render_text->Draw(this);
  canvas_->restore();
}

}  // namespace gfx
<|endoftext|>


<commit_before>#ifndef DUNE_DETAILED_DISCRETIZATIONS_DISCRETEFUNCTIONSPACE_SUBSPACE_AFFINE_HH
#define DUNE_DETAILED_DISCRETIZATIONS_DISCRETEFUNCTIONSPACE_SUBSPACE_AFFINE_HH

// dune-helper-tools includes
#include <dune/helper-tools/function/runtime.hh>

// dune-detailed-discretizations includes
#include <dune/detailed/discretizations/basefunctionset/local/lagrange.hh>
#include <dune/detailed/discretizations/discretefunction/continuous.hh>

namespace Dune
{

namespace Detailed
{

namespace Discretizations {

namespace DiscreteFunctionSpace
{

namespace Sub
{

namespace Affine
{

template< class BaseSpaceImp >
class Dirichlet
{
public:

  typedef BaseSpaceImp
    BaseSpaceType;

  typedef Dirichlet< BaseSpaceType >
    ThisType;

  typedef typename BaseSpaceType::SuperSpaceType
    SuperSpaceType;

  typedef typename BaseSpaceType::FunctionSpaceType
    FunctionSpaceType;

  typedef typename BaseSpaceType::GridPartType
    GridPartType;

  enum{ polynomialOrder = BaseSpaceType::polynomialOrder };

private:
  typedef Dune::HelperTools::Function::Runtime< FunctionSpaceType >
    RuntimeFunctionType;

public:
  typedef Dune::Detailed::Discretizations::DiscreteFunction::Continuous::BlockVector< SuperSpaceType >
    AffineShiftType;

  typedef typename BaseSpaceType::ConstraintsType
    ConstraintsType;

  typedef typename BaseSpaceType::BaseFunctionSetType
    BaseFunctionSetType;

  typedef typename BaseSpaceType::DomainType
    DomainType;

  typedef typename BaseSpaceType::DomainFieldType
    DomainFieldType;

  typedef typename BaseSpaceType::RangeFieldType
    RangeFieldType;

  typedef typename BaseSpaceType::RangeType
    RangeType;

  typedef typename BaseSpaceType::JacobianRangeType
    JacobianRangeType;

  typedef typename BaseSpaceType::HessianRangeType
    HessianRangeType;

  typedef typename BaseSpaceType::MapperType
    MapperType;

  static const unsigned int dimDomain = BaseSpaceType::dimDomain;

  static const unsigned int dimRange = BaseSpaceType::dimRange;

  /**
      @name Convenience Types
      @{
   **/
  typedef typename SuperSpaceType::IteratorType
    IteratorType;

  typedef typename SuperSpaceType::EntityType
    EntityType;
  /**
      @}
   **/

  /**
    \brief  constructor, taking an analytical expression for the boundary data, does a dirichlet projection to generate
            the affine shift
    **/
  Dirichlet( const BaseSpaceType& baseSpace, const std::string expression = "[0.0;0.0;0.0]" )
    : baseSpace_( baseSpace ),
      affineShift_( baseSpace.superSpace(), "affineShift", RuntimeFunctionType( expression ), "dirichlet" )
  {
  }

  /**
    \brief  constructor, taking a discrete function as affine shift
    **/
  Dirichlet( const BaseSpaceType& baseSpace ,const AffineShiftType& affineShift )
    : baseSpace_( baseSpace ),
      affineShift_( affineShift )
  {
  }

  const BaseSpaceType& baseSpace() const
  {
    return baseSpace_;
  }

  const SuperSpaceType& superSpace() const
  {
    return baseSpace_.superSpace();
  }

  const AffineShiftType& affineShift() const
  {
    return affineShift_;
  }

  const GridPartType& gridPart() const
  {
    return baseSpace_.gridPart();
  }

  const BaseFunctionSetType& baseFunctionSet() const
  {
    return baseSpace_.baseFunctionSet();
  }

  int order() const
  {
    return baseSpace_.order();
  }

  const ConstraintsType& constraints() const
  {
    return baseSpace_.constraints();
  }

  const MapperType& map() const
  {
    return baseSpace_.map();
  }

  bool continuous() const
  {
    return baseSpace_.continuous();
  }

  /**
      @name Convenience methods
      @{
   **/
  IteratorType begin() const
  {
    return baseSpace_.gridPart().template begin< 0 >();
  }

  IteratorType end() const
  {
    return baseSpace_.gridPart().template end< 0 >();
  }
  /**
      @}
   **/

private:

  //! copy constructor
  Dirichlet( const ThisType& );

  //! assignment operator
  ThisType& operator=( const ThisType& );

  const BaseSpaceType& baseSpace_;
  const AffineShiftType affineShift_;
}; // end class Dirichlet

} // end namespace Affine

} // end namespace Sub

} // end namespace DiscreteFunctionSpace

} // namespace Discretizations

} // end namespace Detailed

} // end namespace Dune

#endif // DUNE_DETAILED_DISCRETIZATIONS_DISCRETEFUNCTIONSPACE_SUBSPACE_AFFINE_HH
<commit_msg>[discretefunctionspace.sub.affine] update to match the current situation<commit_after>#ifndef DUNE_DETAILED_DISCRETIZATIONS_DISCRETEFUNCTIONSPACE_SUBSPACE_AFFINE_HH
#define DUNE_DETAILED_DISCRETIZATIONS_DISCRETEFUNCTIONSPACE_SUBSPACE_AFFINE_HH

// dune-common
#include <dune/common/shared_ptr.hh>

// dune-stuff
#include <dune/stuff/function/expression.hh>

// dune-detailed-discretizations
#include <dune/detailed/discretizations/discretefunction/default.hh>

namespace Dune {

namespace Detailed {

namespace Discretizations {

namespace DiscreteFunctionSpace {

namespace Sub {

namespace Affine {

template< class BaseSpaceImp, class AffineShiftImp >
class Dirichlet
{
public:

  typedef BaseSpaceImp
    BaseSpaceType;

  typedef AffineShiftImp AffineShiftType;

  typedef Dirichlet< BaseSpaceType, AffineShiftType > ThisType;

  typedef typename BaseSpaceType::SuperSpaceType
    SuperSpaceType;

  typedef typename BaseSpaceType::FunctionSpaceType
    FunctionSpaceType;

  typedef typename BaseSpaceType::GridPartType
    GridPartType;

  typedef typename BaseSpaceType::GridViewType
    GridViewType;

  enum{ polynomialOrder = BaseSpaceType::polynomialOrder };

  typedef typename BaseSpaceType::ConstraintsType
    ConstraintsType;

  typedef typename BaseSpaceType::BaseFunctionSetType
    BaseFunctionSetType;

  typedef typename BaseSpaceType::DomainType
    DomainType;

  typedef typename BaseSpaceType::DomainFieldType
    DomainFieldType;

  typedef typename BaseSpaceType::RangeFieldType
    RangeFieldType;

  typedef typename BaseSpaceType::RangeType
    RangeType;

  typedef typename BaseSpaceType::JacobianRangeType
    JacobianRangeType;

  typedef typename BaseSpaceType::HessianRangeType
    HessianRangeType;

  typedef typename BaseSpaceType::MapperType
    MapperType;

  static const unsigned int dimDomain = BaseSpaceType::dimDomain;

  static const unsigned int dimRange = BaseSpaceType::dimRange;

  typedef typename BaseSpaceType::PatternType PatternType;

  Dirichlet(const BaseSpaceType& baseSpace, const Dune::shared_ptr< const AffineShiftType > affineShift)
    : baseSpace_(baseSpace)
    , affineShift_(affineShift)
  {
  }

  const BaseSpaceType& baseSpace() const
  {
    return baseSpace_;
  }

  const SuperSpaceType& superSpace() const
  {
    return baseSpace_.superSpace();
  }

  const Dune::shared_ptr< const AffineShiftType > affineShift() const
  {
    return affineShift_;
  }

  const GridPartType& gridPart() const
  {
    return baseSpace_.gridPart();
  }

  const GridViewType& gridView() const
  {
    return baseSpace_.gridView();
  }

  const BaseFunctionSetType& baseFunctionSet() const
  {
    return baseSpace_.baseFunctionSet();
  }

  unsigned int order() const
  {
    return baseSpace_.order();
  }

  const ConstraintsType& constraints() const
  {
    return baseSpace_.constraints();
  }

  const MapperType& map() const
  {
    return baseSpace_.map();
  }

  bool continuous() const
  {
    return baseSpace_.continuous();
  }

  template< class LocalGridPartType, class OtherDiscreteFunctionSpaceType >
  Dune::shared_ptr< const PatternType > computeLocalPattern(const LocalGridPartType& localGridPart,
                                                            const OtherDiscreteFunctionSpaceType& other) const
  {
    return baseSpace_.computeLocalPattern(localGridPart, other);
  }

  template< class LocalGridPartType >
  Dune::shared_ptr< const PatternType > computeLocalPattern(const LocalGridPartType& localGridPart) const
  {
    return baseSpace_.computeLocalPattern(localGridPart);
  }

  template< class CouplingGridPartType, class OutsideDiscreteFunctionSpaceType >
  Dune::shared_ptr< const PatternType > computeCouplingPattern(const CouplingGridPartType& couplingGridPart,
                                                               const OutsideDiscreteFunctionSpaceType& outerSpace) const
  {
    return baseSpace_.computeCouplingPattern(couplingGridPart, outerSpace);
  }

  template< class OtherDiscreteFunctionSpaceType>
  Dune::shared_ptr< const PatternType > computePattern(const OtherDiscreteFunctionSpaceType& other) const
  {
    return baseSpace_.computePattern(other);
  }

  Dune::shared_ptr< const PatternType > computePattern() const
  {
    return baseSpace_.computePattern();
  }

private:
  Dirichlet(const ThisType&);
  ThisType& operator=(const ThisType&);

  const BaseSpaceType& baseSpace_;
  const Dune::shared_ptr< const AffineShiftType > affineShift_;
}; // end class Dirichlet

} // end namespace Affine

} // end namespace Sub

} // end namespace DiscreteFunctionSpace

} // namespace Discretizations

} // end namespace Detailed

} // end namespace Dune

#endif // DUNE_DETAILED_DISCRETIZATIONS_DISCRETEFUNCTIONSPACE_SUBSPACE_AFFINE_HH
<|endoftext|>


<commit_before>/** @file

  traffic_ctl

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

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

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

#include "traffic_ctl.h"

static int
metric_get(unsigned argc, const char ** argv)
{
  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments < 1) {
    return CtrlCommandUsage("metric get RECORD [RECORD ...]", NULL, 0);
  }

  for (unsigned i = 0; i < n_file_arguments; ++i) {
    CtrlMgmtRecord record;
    TSMgmtError error;

    error = record.fetch(file_arguments[i]);
    if (error != TS_ERR_OKAY) {
      CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
      return CTRL_EX_ERROR;
    }

    printf("%s %s\n", record.name(), record.c_str());
  }

  return CTRL_EX_OK;
}

static int
metric_match(unsigned argc, const char ** argv)
{
  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments < 1) {
    return CtrlCommandUsage("metric match [OPTIONS] REGEX [REGEX ...]", NULL, 0);
  }

  for (unsigned i = 0; i < n_file_arguments; ++i) {
    CtrlMgmtRecordList reclist;
    TSMgmtError error;

    // XXX filter the results to only match metric records.

    error = reclist.match(file_arguments[i]);
    if (error != TS_ERR_OKAY) {
      CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
      return CTRL_EX_ERROR;
    }

    while (!reclist.empty()) {
      CtrlMgmtRecord record(reclist.next());
      printf("%s %s\n", record.name(), record.c_str());
    }
  }

  return CTRL_EX_OK;
}

static int
metric_clear(unsigned argc, const char ** argv)
{
  int cluster = 0;
  TSMgmtError error;

  const ArgumentDescription opts[] = {
    { "cluster", '-', "Clear cluster metrics", "F", &cluster, NULL, NULL },
  };

  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || n_file_arguments != 0) {
    return CtrlCommandUsage("config clear [OPTIONS]", opts, countof(opts));
  }

  error = TSStatsReset(cluster, NULL);
  if (error != TS_ERR_OKAY) {
    CtrlMgmtError(error, "failed to clear %smetrics", cluster ? "cluster " : "");
    return CTRL_EX_ERROR;
  }

  return CTRL_EX_OK;
}

static int
metric_zero(unsigned argc, const char ** argv)
{
  int cluster = 0;
  TSMgmtError error;

  const ArgumentDescription opts[] = {
    { "cluster", '-', "Zero cluster metrics", "F", &cluster, NULL, NULL },
  };

  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || n_file_arguments == 0) {
    return CtrlCommandUsage("config zero [OPTIONS]", opts, countof(opts));
  }

  for (unsigned i = 0; i < n_file_arguments; ++i) {
    error = TSStatsReset(cluster, NULL);
    if (error != TS_ERR_OKAY) {
      CtrlMgmtError(error, "failed to clear %smetrics", cluster ? "cluster " : "");
      return CTRL_EX_ERROR;
    }
  }

  return CTRL_EX_OK;
}

int
subcommand_metric(unsigned argc, const char ** argv)
{
  const subcommand commands[] =
  {
    { metric_get, "get", "Get one or more metric values" },
    { metric_clear, "clear", "Clear all metric values" },
    { CtrlUnimplementedCommand, "describe", "Show detailed information about one or more metric values" },
    { metric_match, "match", "Get metrics matching a regular expression" },
    { CtrlUnimplementedCommand, "monitor", "Display the value of a metric over time" },

    // We could allow clearing all the metrics in the "clear" subcommand, but that seems error-prone. It
    // would be too easy to just expect a help message and accidentally nuke all the metrics.
    { metric_zero, "zero", "Clear one or more metric values" },
  };

  return CtrlGenericSubcommand("metric", commands, countof(commands), argc, argv);
}
<commit_msg>TS-3367: fix traffic_ctl metric zero subcommand<commit_after>/** @file

  traffic_ctl

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

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

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

#include "traffic_ctl.h"

static int
metric_get(unsigned argc, const char ** argv)
{
  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments < 1) {
    return CtrlCommandUsage("metric get METRIC [METRIC ...]", NULL, 0);
  }

  for (unsigned i = 0; i < n_file_arguments; ++i) {
    CtrlMgmtRecord record;
    TSMgmtError error;

    error = record.fetch(file_arguments[i]);
    if (error != TS_ERR_OKAY) {
      CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
      return CTRL_EX_ERROR;
    }

    printf("%s %s\n", record.name(), record.c_str());
  }

  return CTRL_EX_OK;
}

static int
metric_match(unsigned argc, const char ** argv)
{
  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments < 1) {
    return CtrlCommandUsage("metric match [OPTIONS] REGEX [REGEX ...]", NULL, 0);
  }

  for (unsigned i = 0; i < n_file_arguments; ++i) {
    CtrlMgmtRecordList reclist;
    TSMgmtError error;

    // XXX filter the results to only match metric records.

    error = reclist.match(file_arguments[i]);
    if (error != TS_ERR_OKAY) {
      CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
      return CTRL_EX_ERROR;
    }

    while (!reclist.empty()) {
      CtrlMgmtRecord record(reclist.next());
      printf("%s %s\n", record.name(), record.c_str());
    }
  }

  return CTRL_EX_OK;
}

static int
metric_clear(unsigned argc, const char ** argv)
{
  int cluster = 0;
  TSMgmtError error;

  const ArgumentDescription opts[] = {
    { "cluster", '-', "Clear cluster metrics", "F", &cluster, NULL, NULL },
  };

  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || n_file_arguments != 0) {
    return CtrlCommandUsage("metric clear [OPTIONS]", opts, countof(opts));
  }

  error = TSStatsReset(cluster, NULL);
  if (error != TS_ERR_OKAY) {
    CtrlMgmtError(error, "failed to clear %smetrics", cluster ? "cluster " : "");
    return CTRL_EX_ERROR;
  }

  return CTRL_EX_OK;
}

static int
metric_zero(unsigned argc, const char ** argv)
{
  int cluster = 0;
  TSMgmtError error;

  const ArgumentDescription opts[] = {
    { "cluster", '-', "Zero cluster metrics", "F", &cluster, NULL, NULL },
  };

  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || n_file_arguments < 1) {
    return CtrlCommandUsage("metric zero [OPTIONS] METRIC [METRIC ...]", opts, countof(opts));
  }

  for (unsigned i = 0; i < n_file_arguments; ++i) {
    error = TSStatsReset(cluster, file_arguments[i]);
    if (error != TS_ERR_OKAY) {
      CtrlMgmtError(error, "failed to clear %s", file_arguments[i]);
      return CTRL_EX_ERROR;
    }
  }

  return CTRL_EX_OK;
}

int
subcommand_metric(unsigned argc, const char ** argv)
{
  const subcommand commands[] =
  {
    { metric_get, "get", "Get one or more metric values" },
    { metric_clear, "clear", "Clear all metric values" },
    { CtrlUnimplementedCommand, "describe", "Show detailed information about one or more metric values" },
    { metric_match, "match", "Get metrics matching a regular expression" },
    { CtrlUnimplementedCommand, "monitor", "Display the value of a metric over time" },

    // We could allow clearing all the metrics in the "clear" subcommand, but that seems error-prone. It
    // would be too easy to just expect a help message and accidentally nuke all the metrics.
    { metric_zero, "zero", "Clear one or more metric values" },
  };

  return CtrlGenericSubcommand("metric", commands, countof(commands), argc, argv);
}
<|endoftext|>


<commit_before>// @(#)root/cintex:$Name:  $:$Id: Cintex.cxx,v 1.12 2006/12/08 09:36:06 roiser Exp $
// Author: Pere Mato 2005

// Copyright CERN, CH-1211 Geneva 23, 2004-2005, All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.

#include "Reflex/Callback.h"
#include "Reflex/Type.h"
#include "Reflex/Member.h"
#include "Reflex/Member.h"
#include "Reflex/Builder/ReflexBuilder.h"

#include "Cintex/Cintex.h"
#include "CINTClassBuilder.h"
#include "CINTFunctionBuilder.h"
#include "CINTVariableBuilder.h"
#include "CINTTypedefBuilder.h"
#include "CINTEnumBuilder.h"
#include "ROOTClassEnhancer.h"
#include <iostream>

using namespace ROOT::Reflex;
using namespace ROOT::Cintex;
using namespace std;

//Build the Cintex dictionary on Reflex and convert it to CINT
namespace {
   struct Cintex_dict_t {
   public:
      Cintex_dict_t() {
         //--Reflex class builder
         //NamespaceBuilder( "ROOT::Cintex" );
         Type t_void = TypeBuilder("void");
         Type t_int  = TypeBuilder("int");
         Type t_bool = TypeBuilder("bool");
         ClassBuilderT< Cintex >("Cintex", PUBLIC)
            .AddFunctionMember(FunctionTypeBuilder(t_void), "Enable", Enable, 0, 0, PUBLIC | STATIC)
            .AddFunctionMember(FunctionTypeBuilder(t_void, t_int), "SetDebug", SetDebug, 0, 0, PUBLIC | STATIC)
            .AddFunctionMember(FunctionTypeBuilder(t_int), "Debug", Debug, 0, 0, PUBLIC | STATIC)
            .AddFunctionMember(FunctionTypeBuilder(t_bool), "PropagateClassTypedefs", PropagateClassTypedefs, 0, 0, PUBLIC | STATIC)
            .AddFunctionMember(FunctionTypeBuilder(t_void, t_bool), "SetPropagateClassTypedefs", SetPropagateClassTypedefs, 0, 0, PUBLIC | STATIC);

         //--CINT class builder
         Type t = Type::ByName("Cintex");
         ROOT::Cintex::CINTClassBuilder::Get(t).Setup();
      }
      static void* Enable(void*, const std::vector<void*>&, void*) {
         Cintex::Enable();
         return 0;
      }
      static void* SetDebug(void*, const std::vector<void*>& arg, void*) {
         Cintex::SetDebug(*(bool*)arg[0]);
         return 0;
      }
      static void* Debug(void*, const std::vector<void*>&, void*) {
         static int b = Cintex::Debug();
         return &b;
      }

      static void* PropagateClassTypedefs(void*, const std::vector<void*>&, void*) {
         static bool b = Cintex::PropagateClassTypedefs();
         return &b;
      }

      static void* SetPropagateClassTypedefs(void*, const std::vector<void*>& arg, void*) {
         Cintex::SetPropagateClassTypedefs(*(bool*)arg[0]);
         return 0;
      }

   };
   static Cintex_dict_t s_dict;

   static const char* btypes[] = { "bool", "char", "unsigned char", "short", "unsigned short", "int", "unsigned int",
     "long", "unsigned long", "float", "double", "string" };

   void Declare_additional_CINT_typedefs() {
     char name[256], value[512];
     for ( size_t i = 0; i < sizeof(btypes)/sizeof(char*); i ++ ) {
       //--- vector ---
       sprintf(name,"vector<%s>", btypes[i]);
       sprintf(value,"vector<%s,allocator<%s> >", btypes[i], btypes[i]);
       CINTTypedefBuilder::Set(name, value);
     }
   }
}

namespace ROOT {
   namespace Cintex {

      Cintex& Cintex::Instance() {
         static Cintex s_instance;
         return s_instance;
      }

      Cintex::Cintex() {
         fCallback = new Callback();
         fRootcreator = 0;
         fDbglevel = 0;
         fPropagateClassTypedefs = true;
         fPropagateClassEnums = true;
         fEnabled = false;
      }

      Cintex::~Cintex() {
         if( fCallback ) UninstallClassCallback( fCallback );
         delete fCallback;
      }

      void Cintex::Enable() {
         if ( Instance().fEnabled ) return;
         //---Declare some extra typdefs to please CINT
         Declare_additional_CINT_typedefs();
         //---Install the callback to fothcoming classes ----//
         InstallClassCallback( Instance().fCallback );
         //---Convert to CINT all existing classes ---//
         for( size_t i = 0; i < Type::TypeSize(); i++ ) {

            ( * Instance().fCallback)( Type::TypeAt(i) );
         }
         //---Convert to CINT all existing free functions and variables
         for ( size_t n = 0; n < Scope::ScopeSize(); n++ ) {
            Scope ns = Scope::ScopeAt(n);
            if ( ns.IsNamespace() ) {
               for( size_t m = 0; m < ns.MemberSize(); m++ ) {
                  ( * Instance().fCallback)( ns.MemberAt(m) );
               }
            }
         }
         Instance().fEnabled = true;
      }

      void Cintex::SetROOTCreator(ROOTCreator_t c) {
         Instance().fRootcreator = c;
      }

      ROOTCreator_t Cintex::GetROOTCreator() {
         return Instance().fRootcreator;
      }

      int Cintex::Debug() {
         return Instance().fDbglevel;
      }

      void Cintex::SetDebug(int l) {
         Instance().fDbglevel = l;
      }

      bool Cintex::PropagateClassTypedefs() {
         return Instance().fPropagateClassTypedefs;
      }

      void Cintex::SetPropagateClassTypedefs(bool val) {
         Instance().fPropagateClassTypedefs = val;
      }

      bool Cintex::PropagateClassEnums() {
         return Instance().fPropagateClassEnums;
      }

      void Cintex::SetPropagateClassEnums(bool val) {
         Instance().fPropagateClassEnums = val;
      }

      void Callback::operator () ( const Type& t ) {
         int autoload = G__set_class_autoloading(0); // To avoid recursive loads
         if ( t.IsClass() || t.IsStruct() ) {
            ROOTClassEnhancer enhancer(t);
            enhancer.Setup();
            CINTClassBuilder::Get(t).Setup();
            enhancer.CreateInfo();
         }
         else if ( t.IsTypedef() ) {
            CINTTypedefBuilder::Setup(t);
         }
         else if ( t.IsEnum() ) {
            CINTEnumBuilder::Setup(t);
         }
         G__set_class_autoloading(autoload);
      }

      void Callback::operator () ( const Member& m ) {
         int autoload = G__set_class_autoloading(0); // To avoid recursive loads
         if ( m.IsFunctionMember() ) {
            if( Cintex::Debug() ) cout << "Cintex: Building function " << m.Name(SCOPED|QUALIFIED) << endl;
            CINTFunctionBuilder(m).Setup();
         }
         else if ( m.IsDataMember() ) {
            if( Cintex::Debug() ) cout << "Cintex: Building variable " << m.Name(SCOPED|QUALIFIED) << endl;
            CINTVariableBuilder(m).Setup();
         }
         G__set_class_autoloading(autoload);
      }
   }
}
<commit_msg>From Pere: Fix for problem reported at https://savannah.cern.ch/bugs/?23428<commit_after>// @(#)root/cintex:$Name:  $:$Id: Cintex.cxx,v 1.13 2007/01/13 19:53:41 brun Exp $
// Author: Pere Mato 2005

// Copyright CERN, CH-1211 Geneva 23, 2004-2005, All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.

#include "Reflex/Callback.h"
#include "Reflex/Type.h"
#include "Reflex/Member.h"
#include "Reflex/Member.h"
#include "Reflex/Builder/ReflexBuilder.h"

#include "Cintex/Cintex.h"
#include "CINTClassBuilder.h"
#include "CINTFunctionBuilder.h"
#include "CINTVariableBuilder.h"
#include "CINTTypedefBuilder.h"
#include "CINTEnumBuilder.h"
#include "ROOTClassEnhancer.h"
#include <iostream>

using namespace ROOT::Reflex;
using namespace ROOT::Cintex;
using namespace std;

//Build the Cintex dictionary on Reflex and convert it to CINT
namespace {
   struct Cintex_dict_t {
   public:
      Cintex_dict_t() {
         //--Reflex class builder
         //NamespaceBuilder( "ROOT::Cintex" );
         Type t_void = TypeBuilder("void");
         Type t_int  = TypeBuilder("int");
         Type t_bool = TypeBuilder("bool");
         ClassBuilderT< Cintex >("Cintex", PUBLIC)
            .AddFunctionMember(FunctionTypeBuilder(t_void), "Enable", Enable, 0, 0, PUBLIC | STATIC)
            .AddFunctionMember(FunctionTypeBuilder(t_void, t_int), "SetDebug", SetDebug, 0, 0, PUBLIC | STATIC)
            .AddFunctionMember(FunctionTypeBuilder(t_int), "Debug", Debug, 0, 0, PUBLIC | STATIC)
            .AddFunctionMember(FunctionTypeBuilder(t_bool), "PropagateClassTypedefs", PropagateClassTypedefs, 0, 0, PUBLIC | STATIC)
            .AddFunctionMember(FunctionTypeBuilder(t_void, t_bool), "SetPropagateClassTypedefs", SetPropagateClassTypedefs, 0, 0, PUBLIC | STATIC);

         //--CINT class builder
         Type t = Type::ByName("Cintex");
         ROOT::Cintex::CINTClassBuilder::Get(t).Setup();
      }
      static void* Enable(void*, const std::vector<void*>&, void*) {
         Cintex::Enable();
         return 0;
      }
      static void* SetDebug(void*, const std::vector<void*>& arg, void*) {
         Cintex::SetDebug(*(bool*)arg[0]);
         return 0;
      }
      static void* Debug(void*, const std::vector<void*>&, void*) {
         static int b = Cintex::Debug();
         return &b;
      }

      static void* PropagateClassTypedefs(void*, const std::vector<void*>&, void*) {
         static bool b = Cintex::PropagateClassTypedefs();
         return &b;
      }

      static void* SetPropagateClassTypedefs(void*, const std::vector<void*>& arg, void*) {
         Cintex::SetPropagateClassTypedefs(*(bool*)arg[0]);
         return 0;
      }

   };
   static Cintex_dict_t s_dict;

   static const char* btypes[] = { "bool", "char", "unsigned char", "short", "unsigned short", "int", "unsigned int",
     "long", "unsigned long", "float", "double", "string" };

   void Declare_additional_CINT_typedefs() {
     char name[256], value[512];
     int autoload = G__set_class_autoloading(0); // To avoid recursive loads
     for ( size_t i = 0; i < sizeof(btypes)/sizeof(char*); i ++ ) {
       //--- vector ---
       sprintf(name,"vector<%s>", btypes[i]);
       sprintf(value,"vector<%s,allocator<%s> >", btypes[i], btypes[i]);
       CINTTypedefBuilder::Set(name, value);
     }
     G__set_class_autoloading(autoload);
   }
}

namespace ROOT {
   namespace Cintex {

      Cintex& Cintex::Instance() {
         static Cintex s_instance;
         return s_instance;
      }

      Cintex::Cintex() {
         fCallback = new Callback();
         fRootcreator = 0;
         fDbglevel = 0;
         fPropagateClassTypedefs = true;
         fPropagateClassEnums = true;
         fEnabled = false;
      }

      Cintex::~Cintex() {
         if( fCallback ) UninstallClassCallback( fCallback );
         delete fCallback;
      }

      void Cintex::Enable() {
         if ( Instance().fEnabled ) return;
         //---Declare some extra typdefs to please CINT
         Declare_additional_CINT_typedefs();
         //---Install the callback to fothcoming classes ----//
         InstallClassCallback( Instance().fCallback );
         //---Convert to CINT all existing classes ---//
         for( size_t i = 0; i < Type::TypeSize(); i++ ) {

            ( * Instance().fCallback)( Type::TypeAt(i) );
         }
         //---Convert to CINT all existing free functions and variables
         for ( size_t n = 0; n < Scope::ScopeSize(); n++ ) {
            Scope ns = Scope::ScopeAt(n);
            if ( ns.IsNamespace() ) {
               for( size_t m = 0; m < ns.MemberSize(); m++ ) {
                  ( * Instance().fCallback)( ns.MemberAt(m) );
               }
            }
         }
         Instance().fEnabled = true;
      }

      void Cintex::SetROOTCreator(ROOTCreator_t c) {
         Instance().fRootcreator = c;
      }

      ROOTCreator_t Cintex::GetROOTCreator() {
         return Instance().fRootcreator;
      }

      int Cintex::Debug() {
         return Instance().fDbglevel;
      }

      void Cintex::SetDebug(int l) {
         Instance().fDbglevel = l;
      }

      bool Cintex::PropagateClassTypedefs() {
         return Instance().fPropagateClassTypedefs;
      }

      void Cintex::SetPropagateClassTypedefs(bool val) {
         Instance().fPropagateClassTypedefs = val;
      }

      bool Cintex::PropagateClassEnums() {
         return Instance().fPropagateClassEnums;
      }

      void Cintex::SetPropagateClassEnums(bool val) {
         Instance().fPropagateClassEnums = val;
      }

      void Callback::operator () ( const Type& t ) {
         int autoload = G__set_class_autoloading(0); // To avoid recursive loads
         if ( t.IsClass() || t.IsStruct() ) {
            ROOTClassEnhancer enhancer(t);
            enhancer.Setup();
            CINTClassBuilder::Get(t).Setup();
            enhancer.CreateInfo();
         }
         else if ( t.IsTypedef() ) {
            CINTTypedefBuilder::Setup(t);
         }
         else if ( t.IsEnum() ) {
            CINTEnumBuilder::Setup(t);
         }
         G__set_class_autoloading(autoload);
      }

      void Callback::operator () ( const Member& m ) {
         int autoload = G__set_class_autoloading(0); // To avoid recursive loads
         if ( m.IsFunctionMember() ) {
            if( Cintex::Debug() ) cout << "Cintex: Building function " << m.Name(SCOPED|QUALIFIED) << endl;
            CINTFunctionBuilder(m).Setup();
         }
         else if ( m.IsDataMember() ) {
            if( Cintex::Debug() ) cout << "Cintex: Building variable " << m.Name(SCOPED|QUALIFIED) << endl;
            CINTVariableBuilder(m).Setup();
         }
         G__set_class_autoloading(autoload);
      }
   }
}
<|endoftext|>


<commit_before>//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   driver/Manager.hh
 * \author Thomas M. Evans
 * \date   Fri Mar 14 11:32:36 2014
 * \brief  Manager class definition.
 * \note   Copyright (C) 2014 Oak Ridge National Laboratory, UT-Battelle, LLC.
 */
//---------------------------------------------------------------------------//

#ifndef driver_Manager_hh
#define driver_Manager_hh

#include <sstream>
#include <string>

#include "Teuchos_RCP.hpp"

#include "comm/P_Stream.hh"
#include "spn/Solver_Base.hh"
#include "Problem_Builder.hh"

namespace spn
{

//===========================================================================//
/*!
 * \class Manager
 * \brief Manager class that drives the SPN miniapp.
 */
//===========================================================================//

class Manager
{
  private:
    // Typedefs.
    typedef Problem_Builder::RCP_ParameterList     RCP_ParameterList;
    typedef Problem_Builder::RCP_Mesh              RCP_Mesh;
    typedef Problem_Builder::RCP_Indexer           RCP_Indexer;
    typedef Problem_Builder::RCP_Global_Data       RCP_Global_Data;
    typedef Problem_Builder::RCP_Mat_DB            RCP_Mat_DB;
    typedef profugus::Solver_Base                  Solver_Base_t;
    typedef Solver_Base_t::RCP_Dimensions          RCP_Dimensions;
    typedef Teuchos::RCP<profugus::State>          RCP_State;
    typedef Teuchos::RCP<Solver_Base_t>            RCP_Solver_Base;
    typedef profugus::Isotropic_Source             External_Source_t;
    typedef Teuchos::RCP<External_Source_t>        RCP_External_Source;

    // >>> DATA

    // Problem database.
    RCP_ParameterList d_db;

    // Mesh objects
    RCP_Mesh        d_mesh;
    RCP_Indexer     d_indexer;
    RCP_Global_Data d_gdata;

    // Material database.
    RCP_Mat_DB d_mat;

    // Problem state.
    RCP_State d_state;

    // Problem dimensions.
    RCP_Dimensions d_dim;

    // Solvers
    RCP_Solver_Base d_solver_base;

    // External source for fixed source problems.
    RCP_External_Source d_external_source;

  public:
    // Constructor.
    Manager();

    // Setup the problem.
    void setup(const std::string &xml_file);

    // Solve the problem.
    void solve();

    // Output.
    void output();

  private:
    // >>> IMPLEMENTATION

    // Processor.
    int d_node, d_nodes;

    // Problem name.
    std::string d_problem_name;

    //! Output messages in a common format.
#define SCREEN_MSG(stream)                            \
    {                                                 \
        std::ostringstream m;                         \
        m << ">>> " << stream;                        \
        profugus::pcout << m.str() << profugus::endl; \
    }
};

} // end namespace spn

#endif // driver_Manager_hh

//---------------------------------------------------------------------------//
//                 end of Manager.hh
//---------------------------------------------------------------------------//
<commit_msg>Adding accessor to solver from spn manager.<commit_after>//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   driver/Manager.hh
 * \author Thomas M. Evans
 * \date   Fri Mar 14 11:32:36 2014
 * \brief  Manager class definition.
 * \note   Copyright (C) 2014 Oak Ridge National Laboratory, UT-Battelle, LLC.
 */
//---------------------------------------------------------------------------//

#ifndef driver_Manager_hh
#define driver_Manager_hh

#include <sstream>
#include <string>

#include "Teuchos_RCP.hpp"

#include "comm/P_Stream.hh"
#include "spn/Solver_Base.hh"
#include "Problem_Builder.hh"

namespace spn
{

//===========================================================================//
/*!
 * \class Manager
 * \brief Manager class that drives the SPN miniapp.
 */
//===========================================================================//

class Manager
{
  private:
    // Typedefs.
    typedef Problem_Builder::RCP_ParameterList     RCP_ParameterList;
    typedef Problem_Builder::RCP_Mesh              RCP_Mesh;
    typedef Problem_Builder::RCP_Indexer           RCP_Indexer;
    typedef Problem_Builder::RCP_Global_Data       RCP_Global_Data;
    typedef Problem_Builder::RCP_Mat_DB            RCP_Mat_DB;
    typedef profugus::Solver_Base                  Solver_Base_t;
    typedef Solver_Base_t::RCP_Dimensions          RCP_Dimensions;
    typedef Teuchos::RCP<profugus::State>          RCP_State;
    typedef Teuchos::RCP<Solver_Base_t>            RCP_Solver_Base;
    typedef profugus::Isotropic_Source             External_Source_t;
    typedef Teuchos::RCP<External_Source_t>        RCP_External_Source;

    // >>> DATA

    // Problem database.
    RCP_ParameterList d_db;

    // Mesh objects
    RCP_Mesh        d_mesh;
    RCP_Indexer     d_indexer;
    RCP_Global_Data d_gdata;

    // Material database.
    RCP_Mat_DB d_mat;

    // Problem state.
    RCP_State d_state;

    // Problem dimensions.
    RCP_Dimensions d_dim;

    // Solvers
    RCP_Solver_Base d_solver_base;

    // External source for fixed source problems.
    RCP_External_Source d_external_source;

  public:
    // Constructor.
    Manager();

    // Setup the problem.
    void setup(const std::string &xml_file);

    // Solve the problem.
    void solve();

    // Output.
    void output();

    // Access solver
    Teuchos::RCP<const Solver_Base_t> get_solver() const
    {
        return d_solver_base;
    }

  private:
    // >>> IMPLEMENTATION

    // Processor.
    int d_node, d_nodes;

    // Problem name.
    std::string d_problem_name;

    //! Output messages in a common format.
#define SCREEN_MSG(stream)                            \
    {                                                 \
        std::ostringstream m;                         \
        m << ">>> " << stream;                        \
        profugus::pcout << m.str() << profugus::endl; \
    }
};

} // end namespace spn

#endif // driver_Manager_hh

//---------------------------------------------------------------------------//
//                 end of Manager.hh
//---------------------------------------------------------------------------//
<|endoftext|>


<commit_before>#include "discord.h"
#include "system.h"
#include "../logger.h"
#include "../util.h"
#include "../config.h"
#include <sleepy_discord/sleepy_discord.h>

namespace shanghai {
namespace system {

namespace {

const std::string HELP_TEXT =
R"(/help
    Show this help
/info
    Print system information
/server
    Show server list
/ch <server_id>
    Show channel list
)";

struct DiscordConfig {
	std::string DefaultReply = "";
};

}	// namespace

class Discord::MyClient : public SleepyDiscord::DiscordClient {
public:
	// コンストラクタ
	MyClient(const DiscordConfig &conf,
		const std::string &token, char numOfThreads)
		: SleepyDiscord::DiscordClient(token, numOfThreads),
		m_conf(conf)
	{}
	virtual ~MyClient() = default;

private:
	DiscordConfig m_conf;

	// コマンドとして処理出来たら true
	bool ExecuteCommand(SleepyDiscord::Snowflake<SleepyDiscord::Channel> ch,
		std::vector<std::string> args)
	{
		if (args.size() == 0) {
			return false;
		}
		if (args.at(0) == "/help") {
			sendMessage(ch, HELP_TEXT);
			return true;
		}
		else if (args.at(0) == "/info") {
			auto &sys_info = system::Get().sys_info;
			system::SysInfoData data = sys_info.Get();
			std::string msg = util::Format(
				"Build Type: {0}\n"
				"Branch: {1}\n"
				"Commit: {2}\n"
				"White: {3}\n"
				"Black: {4}",
				{
					data.build_type, data.git_branch, data.git_hash,
					std::to_string(data.white), std::to_string(data.black)
				});
			sendMessage(ch, msg);
			return true;
		}
		else if (args.at(0) == "/server") {
			std::vector<SleepyDiscord::Server> resp = getServers();
			std::string msg = util::Format("{0} Server(s)",
				{std::to_string(resp.size())});
			for (const auto &server : resp) {
				msg += '\n';
				msg += server.ID;
				msg += ' ';
				msg += server.name;
			}
			sendMessage(ch, msg);
			return true;
		}
		else if (args.at(0) == "/ch") {
			if (args.size() < 2) {
				sendMessage(ch, "Argument error.");
				return true;
			}
			std::vector<SleepyDiscord::Channel> resp =
				getServerChannels(args.at(1));
			std::string msg = util::Format("Channel(s)",
				{std::to_string(resp.size())});
			for (const auto &ch : resp) {
				if (ch.type != SleepyDiscord::Channel::ChannelType::SERVER_TEXT) {
					continue;
				}
				msg += '\n';
				msg += ch.ID;
				msg += ' ';
				msg += ch.name;
			}
			sendMessage(ch, msg);
			return true;
		}
		else {
			return false;
		}
	}

protected:
	void onReady(SleepyDiscord::Ready ready) override
	{
		logger.Log(LogLevel::Info, "[Discord] Ready");
		{
			const SleepyDiscord::User &user = ready.user;
			const std::string &id = user.ID;
			logger.Log(LogLevel::Info, "[Discord] user %s %s bot:%s",
				id.c_str(), user.username.c_str(),
				user.bot ? "Yes" : "No");
		}
	}

	void onMessage(SleepyDiscord::Message message) override
	{
		// ミラーマッチ対策として bot には反応しないようにする
		if (message.author.bot) {
			return;
		}

		logger.Log(LogLevel::Info, "[Discord] Message");
		logger.Log(LogLevel::Info, "[Discord] %s", message.content.c_str());
		// メンション時のみでフィルタ
		if (message.isMentioned(getID())) {
			// 半角スペースで区切ってメンションを削除
			// 例: <@!123456789>
			std::vector<std::string> tokens = util::Split(
				message.content, ' ', true);
			auto result = std::remove_if(tokens.begin(), tokens.end(),
				[](const std::string &s) {
					return s.find("<") == 0 && s.rfind(">") == s.size() - 1;
				});
			tokens.erase(result, tokens.end());

			// コマンドとして実行
			// できなかったらデフォルト返信
			if (!ExecuteCommand(message.channelID, tokens)) {
				std::string msg = m_conf.DefaultReply;
				msg += "\n(Help command: /help)";
				sendMessage(message.channelID, msg);
			}
		}
	}

	void onError(SleepyDiscord::ErrorCode errorCode,
		const std::string errorMessage) override
	{
		logger.Log(LogLevel::Error, "[Discord] %s", errorMessage.c_str());
	}
};

Discord::Discord()
{
	logger.Log(LogLevel::Info, "Initialize Discord...");

	bool enabled = config.GetBool({"Discord", "Enabled"});
	std::string token = config.GetStr({"Discord", "Token"});

	if (enabled) {
		DiscordConfig dconf;
		dconf.DefaultReply = config.GetStr({"Discord", "DefaultReply"});

		m_client = std::make_unique<MyClient>(
			dconf, token, SleepyDiscord::USE_RUN_THREAD);
		m_thread = std::thread([this]() {
			try {
				m_client->run();
			}
			catch (std::exception &e) {
				logger.Log(LogLevel::Error, "Discord thread error: %s", e.what());
			}
		});
		logger.Log(LogLevel::Info, "Initialize Discord OK");
	}
	else {
		logger.Log(LogLevel::Info, "Initialize Discord OK (Disabled)");
	}
}

Discord::~Discord()
{
	logger.Log(LogLevel::Info, "Finalize Discord...");
	if (m_client != nullptr) {
		logger.Log(LogLevel::Info, "Quit asio...");
		logger.Flush();
		m_client->quit();

		logger.Log(LogLevel::Info, "Join discord thread...");
		logger.Flush();
		m_thread.join();
	}
	logger.Log(LogLevel::Info, "Finalize Discord OK");
}

}	// namespace system
}	// namespace shanghai
<commit_msg>/dice n 面ダイス m 回機能<commit_after>#include "discord.h"
#include "system.h"
#include "../logger.h"
#include "../util.h"
#include "../config.h"
#include <sleepy_discord/sleepy_discord.h>
#include <random>

namespace shanghai {
namespace system {

namespace {

const std::string HELP_TEXT =
R"(/help
    Show this help
/info
    Print system information
/server
    Show server list
/ch <server_id>
    Show channel list
/dice [<max>] [<times>]
    Roll a dice
)";

struct DiscordConfig {
	std::string DefaultReply = "";
};

}	// namespace

class Discord::MyClient : public SleepyDiscord::DiscordClient {
public:
	// コンストラクタ
	MyClient(const DiscordConfig &conf,
		const std::string &token, char numOfThreads)
		: SleepyDiscord::DiscordClient(token, numOfThreads),
		m_conf(conf)
	{}
	virtual ~MyClient() = default;

private:
	DiscordConfig m_conf;
	// 非決定論的乱数生成器 (連打禁止)
	std::random_device m_rng;

	// コマンドとして処理出来たら true
	bool ExecuteCommand(SleepyDiscord::Snowflake<SleepyDiscord::Channel> ch,
		std::vector<std::string> args)
	{
		if (args.size() == 0) {
			return false;
		}
		if (args.at(0) == "/help") {
			sendMessage(ch, HELP_TEXT);
			return true;
		}
		else if (args.at(0) == "/info") {
			auto &sys_info = system::Get().sys_info;
			system::SysInfoData data = sys_info.Get();
			std::string msg = util::Format(
				"Build Type: {0}\n"
				"Branch: {1}\n"
				"Commit: {2}\n"
				"White: {3}\n"
				"Black: {4}",
				{
					data.build_type, data.git_branch, data.git_hash,
					std::to_string(data.white), std::to_string(data.black)
				});
			sendMessage(ch, msg);
			return true;
		}
		else if (args.at(0) == "/server") {
			std::vector<SleepyDiscord::Server> resp = getServers();
			std::string msg = util::Format("{0} Server(s)",
				{std::to_string(resp.size())});
			for (const auto &server : resp) {
				msg += '\n';
				msg += server.ID;
				msg += ' ';
				msg += server.name;
			}
			sendMessage(ch, msg);
			return true;
		}
		else if (args.at(0) == "/ch") {
			if (args.size() < 2) {
				sendMessage(ch, "Argument error.");
				return true;
			}
			std::vector<SleepyDiscord::Channel> resp =
				getServerChannels(args.at(1));
			std::string msg = util::Format("Channel(s)",
				{std::to_string(resp.size())});
			for (const auto &ch : resp) {
				if (ch.type != SleepyDiscord::Channel::ChannelType::SERVER_TEXT) {
					continue;
				}
				msg += '\n';
				msg += ch.ID;
				msg += ' ';
				msg += ch.name;
			}
			sendMessage(ch, msg);
			return true;
		}
		else if (args.at(0) == "/dice") {
			const uint64_t DICE_MAX = 1ULL << 56;
			const uint64_t COUNT_MAX = 100;
			//     d * c < U64
			// <=> d < U64 / c
			static_assert(
				DICE_MAX <
				std::numeric_limits<uint64_t>::max() / COUNT_MAX);

			uint64_t d = 6;
			uint64_t count = 1;
			bool error = false;
			if (args.size() >= 2) {
				try {
					d = util::to_uint64(args.at(1), 1, DICE_MAX);
				}
				catch(...){
					error = true;
				}
			}
			if (args.size() >= 3) {
				try {
					count = util::to_uint64(args.at(2), 1, COUNT_MAX);
				}
				catch(...){
					error = true;
				}
			}
			if (error) {
				std::string msg = util::Format(
					"1 <= DICE <= {0}\n"
					"1 <= COUNT <= {1}",
					{std::to_string(DICE_MAX), std::to_string(COUNT_MAX)});
				sendMessage(ch, msg);
				return true;
			}

			std::string seq = "";
			uint64_t sum = 0;
			for (uint64_t i = 0; i < count; i++) {
				std::uniform_int_distribution<uint64_t> dist(1, d);
				uint64_t r = dist(m_rng);
				sum += r;
				if (seq.size() != 0) {
					seq += ", ";
				}
				seq += std::to_string(r);
			}
			std::string msg;
			if (count == 1) {
				msg = std::to_string(sum);
			} else {
				msg = util::Format("{0}\n({1})", {std::to_string(sum), seq});
			}
			sendMessage(ch, msg);
			return true;
		}
		else {
			return false;
		}
	}

protected:
	void onReady(SleepyDiscord::Ready ready) override
	{
		logger.Log(LogLevel::Info, "[Discord] Ready");
		{
			const SleepyDiscord::User &user = ready.user;
			const std::string &id = user.ID;
			logger.Log(LogLevel::Info, "[Discord] user %s %s bot:%s",
				id.c_str(), user.username.c_str(),
				user.bot ? "Yes" : "No");
		}
	}

	void onMessage(SleepyDiscord::Message message) override
	{
		// ミラーマッチ対策として bot には反応しないようにする
		if (message.author.bot) {
			return;
		}

		logger.Log(LogLevel::Info, "[Discord] Message");
		logger.Log(LogLevel::Info, "[Discord] %s", message.content.c_str());
		// メンション時のみでフィルタ
		if (message.isMentioned(getID())) {
			// 半角スペースで区切ってメンションを削除
			// 例: <@!123456789>
			std::vector<std::string> tokens = util::Split(
				message.content, ' ', true);
			auto result = std::remove_if(tokens.begin(), tokens.end(),
				[](const std::string &s) {
					return s.find("<") == 0 && s.rfind(">") == s.size() - 1;
				});
			tokens.erase(result, tokens.end());

			// コマンドとして実行
			// できなかったらデフォルト返信
			if (!ExecuteCommand(message.channelID, tokens)) {
				std::string msg = m_conf.DefaultReply;
				msg += "\n(Help command: /help)";
				sendMessage(message.channelID, msg);
			}
		}
	}

	void onError(SleepyDiscord::ErrorCode errorCode,
		const std::string errorMessage) override
	{
		logger.Log(LogLevel::Error, "[Discord] %s", errorMessage.c_str());
	}
};

Discord::Discord()
{
	logger.Log(LogLevel::Info, "Initialize Discord...");

	bool enabled = config.GetBool({"Discord", "Enabled"});
	std::string token = config.GetStr({"Discord", "Token"});

	if (enabled) {
		DiscordConfig dconf;
		dconf.DefaultReply = config.GetStr({"Discord", "DefaultReply"});

		m_client = std::make_unique<MyClient>(
			dconf, token, SleepyDiscord::USE_RUN_THREAD);
		m_thread = std::thread([this]() {
			try {
				m_client->run();
			}
			catch (std::exception &e) {
				logger.Log(LogLevel::Error, "Discord thread error: %s", e.what());
			}
		});
		logger.Log(LogLevel::Info, "Initialize Discord OK");
	}
	else {
		logger.Log(LogLevel::Info, "Initialize Discord OK (Disabled)");
	}
}

Discord::~Discord()
{
	logger.Log(LogLevel::Info, "Finalize Discord...");
	if (m_client != nullptr) {
		logger.Log(LogLevel::Info, "Quit asio...");
		logger.Flush();
		m_client->quit();

		logger.Log(LogLevel::Info, "Join discord thread...");
		logger.Flush();
		m_thread.join();
	}
	logger.Log(LogLevel::Info, "Finalize Discord OK");
}

}	// namespace system
}	// namespace shanghai
<|endoftext|>